Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / mojo / public / dart / src / codec.dart
blob003fcc1d26aeedb3f3ac8b6fa8460ef814c03c30
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.
5 part of bindings;
7 const int kAlignment = 8;
8 const int kArrayHeaderSize = 8;
9 const int kStructHeaderSize = 8;
10 const int kMessageHeaderSize = 16;
11 const int kMessageWithRequestIDHeaderSize = 24;
12 const int kMapStructPayloadSize = 16;
13 const int kStructHeaderNumBytesOffset = 0;
14 const int kStructHeaderNumFieldsOffset = 4;
15 const int kEncodedInvalidHandleValue = 0xffffffff;
16 const String kErrorUnsigned = "Passing negative value to unsigned encoder";
19 int align(int size) => size + (kAlignment - (size % kAlignment)) % kAlignment;
20 bool isAligned(offset) => (offset >= 0) && ((offset % kAlignment) == 0);
23 Uint8List utf8OfString(String s) =>
24   (new Uint8List.fromList((const Utf8Encoder()).convert(s)));
27 String stringOfUtf8(Uint8List bytes) =>
28     (const Utf8Decoder()).convert(bytes.toList());
31 // Given an argument that is either a Type or an instance:
32 // Invoke the static method "decode" of the Type, or the instance method
33 // "decode" of the instance, on the MojoDecoder.
34 Object _callDecode(Object typeOrInstance, MojoDecoder decoder) {
35   if (typeOrInstance is Type) {
36     return reflectClass(typeOrInstance).invoke(#decode, [decoder]).reflectee;
37   } else {
38     return typeOrInstance.decode(decoder);
39   }
43 // Given an argument that is either a Type or an instance:
44 // Invoke the static method "encode" of the Type, or the instance method
45 // "encode" of the instance, on the MojoEncoder and value to be encoded.
46 void _callEncode(Object typeOrInstance, MojoEncoder encoder, Object val) {
47   if (typeOrInstance is Type) {
48     reflectClass(typeOrInstance).invoke(#encode, [encoder, val]);
49   } else {
50     typeOrInstance.encode(encoder, val);
51   }
55 // Given an argument that is either a Type or an instance:
56 // Invoke the static getter "encodedSize" of the Type, or the instance getter
57 // "encodedSize" of the instance, and return the result.
58 int getEncodedSize(Object typeOrInstance) {
59   if (typeOrInstance is Type) {
60     return reflectClass(typeOrInstance).getField(#encodedSize).reflectee;
61   } else {
62     return typeOrInstance.encodedSize;
63   }
67 class MojoDecoder {
68   ByteData buffer;
69   List<int> handles;
70   int base;
71   int next;
73   MojoDecoder(this.buffer, this.handles, this.base) {
74     next = base;
75   }
77   void skip(int offset) {
78     next += offset;
79   }
81   int readInt8() {
82     int result = buffer.getInt8(next);
83     next += 1;
84     return result;
85   }
87   int readUint8() {
88     int result = buffer.getUint8(next);
89     next += 1;
90     return result;
91   }
93   int readInt16() {
94     int result = buffer.getInt16(next, Endianness.LITTLE_ENDIAN);
95     next += 2;
96     return result;
97   }
99   int readUint16() {
100     int result = buffer.getUint16(next, Endianness.LITTLE_ENDIAN);
101     next += 2;
102     return result;
103   }
105   int readInt32() {
106     int result = buffer.getInt32(next, Endianness.LITTLE_ENDIAN);
107     next += 4;
108     return result;
109   }
111   int readUint32() {
112     int result = buffer.getUint32(next, Endianness.LITTLE_ENDIAN);
113     next += 4;
114     return result;
115   }
117   int readInt64() {
118     int result = buffer.getInt64(next, Endianness.LITTLE_ENDIAN);
119     next += 8;
120     return result;
121   }
123   int readUint64() {
124     int result = buffer.getUint64(next, Endianness.LITTLE_ENDIAN);
125     next += 8;
126     return result;
127   }
129   double readFloat() {
130     double result = buffer.getFloat32(next,Endianness.LITTLE_ENDIAN);
131     next += 4;
132     return result;
133   }
135   double readDouble() {
136     double result = buffer.getFloat64(next, Endianness.LITTLE_ENDIAN);
137     next += 8;
138     return result;
139   }
141   int decodePointer() {
142     int offsetPointer = next;
143     int offset = readUint64();
144     if (offset == 0) {
145       return 0;
146     }
147     return offsetPointer + offset;
148   }
150   MojoDecoder decodeAndCreateDecoder(int offset) {
151     return new MojoDecoder(buffer, handles, offset);
152   }
154   int decodeHandle() {
155     return handles[readUint32()];
156   }
158   String decodeString() {
159     int numBytes = readUint32();
160     int numElements = readUint32();
161     int base = next;
162     next += numElements;
163     return stringOfUtf8(buffer.buffer.asUint8List(base, numElements));
164   }
166   List decodeArray(Object type) {
167     int numBytes = readUint32();
168     int numElements = readUint32();
169     if (type == PackedBool) {
170       int b;
171       List<bool> result = new List<bool>(numElements);
172       for (int i = 0; i < numElements; i++) {
173         if ((i % 8) == 0) {
174           b = readUint8();
175         }
176         result[i] = ((b & (1 << (i % 8)) != 0) ? true : false);
177       }
178       return result;
179     } else {
180       List result = new List(numElements);
181       for (int i = 0; i < numElements; i++) {
182         result[i] = _callDecode(type, this);
183       }
184       return result;
185     }
186   }
188   Object decodeStruct(Object t) {
189     return _callDecode(t, this);
190   }
192   Object decodeStructPointer(Object t) {
193     int pointer = decodePointer();
194     if (pointer == 0) {
195       return null;
196     }
197     return _callDecode(t, decodeAndCreateDecoder(pointer));
198   }
200   List decodeArrayPointer(Object type) {
201     int pointer = decodePointer();
202     if (pointer == 0) {
203       return null;
204     }
205     return decodeAndCreateDecoder(pointer).decodeArray(type);
206   }
208   String decodeStringPointer() {
209     int pointer = decodePointer();
210     if (pointer == 0) {
211       return null;
212     }
213     return decodeAndCreateDecoder(pointer).decodeString();
214   }
216   Map decodeMap(Object keyType, Object valType) {
217     skip(4);  // number of bytes.
218     skip(4);  // number of fields.
219     List keys = decodeArrayPointer(keyType);
220     List values = decodeArrayPointer(valType);
221     return new Map.fromIterables(keys, values);
222   }
224   Map decodeMapPointer(Object keyType, Object valType) {
225     int pointer = this.decodePointer();
226     if (pointer == 0) {
227       return null;
228     }
229     MojoDecoder decoder = decodeAndCreateDecoder(pointer);
230     return decoder.decodeMap(keyType, valType);
231   }
235 class MojoEncoder {
236   ByteData buffer;
237   List<int> handles;
238   int base;
239   int next;
240   int extent;
242   MojoEncoder(this.buffer, this.handles, this.base, this.extent) {
243     next = base;
244   }
246   void skip(int offset) {
247     next += offset;
248   }
250   void writeInt8(int val) {
251     buffer.setInt8(next, val);
252     next += 1;
253   }
255   void writeUint8(int val) {
256     if (val < 0) {
257       throw new ArgumentError("$kErrorUnsigned: $val");
258     }
259     buffer.setUint8(next, val);
260     next += 1;
261   }
263   void writeInt16(int val) {
264     buffer.setInt16(next, val, Endianness.LITTLE_ENDIAN);
265     next += 2;
266   }
268   void writeUint16(int val) {
269     if (val < 0) {
270       throw new ArgumentError("$kErrorUnsigned: $val");
271     }
272     buffer.setUint16(next, val, Endianness.LITTLE_ENDIAN);
273     next += 2;
274   }
276   void writeInt32(int val) {
277     buffer.setInt32(next, val, Endianness.LITTLE_ENDIAN);
278     next += 4;
279   }
281   void writeUint32(int val) {
282     if (val < 0) {
283       throw new ArgumentError("$kErrorUnsigned: $val");
284     }
285     buffer.setUint32(next, val, Endianness.LITTLE_ENDIAN);
286     next += 4;
287   }
289   void writeInt64(int val) {
290     buffer.setInt64(next, val, Endianness.LITTLE_ENDIAN);
291     next += 8;
292   }
294   void writeUint64(int val) {
295     if (val < 0) {
296       throw new ArgumentError("$kErrorUnsigned: $val");
297     }
298     buffer.setUint64(next, val, Endianness.LITTLE_ENDIAN);
299     next += 8;
300   }
302   void writeFloat(double val) {
303     buffer.setFloat32(next, val, Endianness.LITTLE_ENDIAN);
304     next += 4;
305   }
307   void writeDouble(double val) {
308     buffer.setFloat64(next, val, Endianness.LITTLE_ENDIAN);
309     next += 8;
310   }
312   void encodePointer(int pointer) {
313     if (pointer == null) {
314       writeUint64(0);
315       return;
316     }
317     int offset = pointer - next;
318     writeUint64(offset);
319   }
321   void grow(int new_size) {
322     Uint8List new_buffer = new Uint8List(new_size);
323     new_buffer.setRange(0, next, buffer.buffer.asUint8List());
324     buffer = new_buffer.buffer.asByteData();
325   }
327   int alloc(int size_request) {
328     int pointer = extent;
329     extent += size_request;
330     if (extent > buffer.lengthInBytes) {
331       int new_size = buffer.lengthInBytes + size_request;
332       new_size += new_size ~/ 2;
333       grow(new_size);
334     }
335     return pointer;
336   }
338   MojoEncoder createAndEncodeEncoder(int size) {
339     int pointer = alloc(align(size));
340     encodePointer(pointer);
341     return new MojoEncoder(buffer, handles, pointer, extent);
342   }
344   void encodeHandle(int handle) {
345     handles.add(handle);
346     writeUint32(handles.length - 1);
347   }
349   void encodeString(String val) {
350     Uint8List utf8string = utf8OfString(val);
351     int numElements = utf8string.lengthInBytes;
352     int numBytes = kArrayHeaderSize + numElements;
353     writeUint32(numBytes);
354     writeUint32(numElements);
355     buffer.buffer.asUint8List().setRange(next, next + numElements, utf8string);
356     next += numElements;
357   }
359   void encodeArray(Object t, List val, [int numElements, int encodedSize]) {
360     if (numElements == null) {
361       numElements = val.length;
362     }
363     if (encodedSize == null) {
364       encodedSize = kArrayHeaderSize + (getEncodedSize(t) * numElements);
365     }
367     writeUint32(encodedSize);
368     writeUint32(numElements);
370     if (t == PackedBool) {
371       int b = 0;
372       for (int i = 0; i < numElements; i++) {
373         if (val[i]) {
374           b |= (1 << (i % 8));
375         }
376         if (((i % 8) == 7) || (i == (numElements - 1))) {
377           Uint8.encode(this, b);
378         }
379       }
380     } else {
381       for (int i = 0; i < numElements; i++) {
382         _callEncode(t, this, val[i]);
383       }
384     }
385   }
387   void encodeStruct(Object t, Object val) {
388     _callEncode(t, this, val);
389   }
391   void encodeStructPointer(Object t, Object val) {
392     if (val == null) {
393       encodePointer(val);
394       return;
395     }
396     MojoEncoder encoder = createAndEncodeEncoder(getEncodedSize(t));
397     _callEncode(t, encoder, val);
398     extent = encoder.extent;
399     buffer = encoder.buffer;
400   }
402   void encodeArrayPointer(Object t, List val) {
403     if (val == null) {
404       encodePointer(val);
405       return;
406     }
407     int numElements = val.length;
408     int encodedSize = kArrayHeaderSize + ((t == PackedBool) ?
409         (numElements / 8).ceil() : (getEncodedSize(t) * numElements));
410     MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
411     encoder.encodeArray(t, val, numElements, encodedSize);
412     extent = encoder.extent;
413     buffer = encoder.buffer;
414   }
416   void encodeStringPointer(String val) {
417     if (val == null) {
418       encodePointer(val);
419       return;
420     }
421     int encodedSize = kArrayHeaderSize + utf8OfString(val).lengthInBytes;
422     MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
423     encoder.encodeString(val);
424     extent = encoder.extent;
425     buffer = encoder.buffer;
426   }
428   void encodeMap(Object keyType, Object valType, Map val) {
429     List keys = val.keys;
430     List vals = val.values;
431     writeUint32(kStructHeaderSize + kMapStructPayloadSize);
432     writeUint32(2);
433     encodeArrayPointer(keyType, keys);
434     encodeArrayPointer(valType, vals);
435   }
437   void encodeMapPointer(Object keyTYpe, Object valType, Map val) {
438     if (val == null) {
439       encodePointer(val);
440       return;
441     }
442     int encodedSize = kStructHeaderSize + kMapStructPayloadSize;
443     MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
444     encoder.encodeMap(keyType, valType, val);
445     extent = encoder.extent;
446     buffer = encoder.buffer;
447   }
451 const int kMessageNameOffset = kStructHeaderSize;
452 const int kMessageFlagsOffset = kMessageNameOffset + 4;
453 const int kMessageRequestIDOffset = kMessageFlagsOffset + 4;
454 const int kMessageExpectsResponse = 1 << 0;
455 const int kMessageIsResponse = 1 << 1;
457 class Message {
458   ByteData buffer;
459   List<int> handles;
461   Message(this.buffer, this.handles);
463   int getHeaderNumBytes() => buffer.getUint32(kStructHeaderNumBytesOffset);
464   int getHeaderNumFields() => buffer.getUint32(kStructHeaderNumFieldsOffset);
465   int getName() => buffer.getUint32(kMessageNameOffset);
466   int getFlags() => buffer.getUint32(kMessageFlagsOffset);
467   bool isResponse() => (getFlags() & kMessageIsResponse) != 0;
468   bool expectsResponse() => (getFlags() & kMessageExpectsResponse) != 0;
470   void setRequestID(int id) {
471     buffer.setUint64(kMessageRequestIDOffset, id);
472   }
476 class MessageBuilder {
477   MojoEncoder encoder;
478   List<int> handles;
480   MessageBuilder(int name, int payloadSize) {
481     int numBytes = kMessageHeaderSize + payloadSize;
482     var buffer = new ByteData(numBytes);
483     handles = [];
485     encoder = new MojoEncoder(buffer, handles, 0, kMessageHeaderSize);
486     encoder.writeUint32(kMessageHeaderSize);
487     encoder.writeUint32(2);  // num_fields;
488     encoder.writeUint32(name);
489     encoder.writeUint32(0);  // flags.
490   }
492   MojoEncoder createEncoder(int size) {
493     encoder = new MojoEncoder(encoder.buffer,
494                               handles,
495                               encoder.next,
496                               encoder.next + size);
497     return encoder;
498   }
500   void encodeStruct(Object t, Object val) {
501     encoder = createEncoder(getEncodedSize(t));
502     _callEncode(t, encoder, val);
503   }
505   ByteData _trimBuffer() {
506     return new ByteData.view(encoder.buffer.buffer, 0, encoder.extent);
507   }
509   Message finish() {
510     Message message = new Message(_trimBuffer(), handles);
511     encoder = null;
512     handles = null;
513     return message;
514   }
518 class MessageWithRequestIDBuilder extends MessageBuilder {
519   MessageWithRequestIDBuilder(
520       int name, int payloadSize, int flags, int requestID) {
521     int numBytes = kMessageWithRequestIDHeaderSize + payloadSize;
522     buffer = new ByteData(numBytes);
523     handles = [];
524     base = 0;
526     encoder = createEncoder(0, kMessageWithRequestIDHeaderSize);
527     encoder.writeUint32(kMessageWithRequestIDHeaderSize);
528     encoder.writeUint32(3);  // num_fields.
529     encoder.writeUint32(name);
530     encoder.writeUint32(flags);
531     encoder.writeUint64(requestID);
532     base = encoder.next;
533     buffer = encoder.buffer;
534   }
538 class MessageReader {
539   MojoDecoder decoder;
540   int payloadSize;
541   int name;
542   int flags;
543   int requestID;
545   MessageReader(Message message) {
546     decoder = new MojoDecoder(message.buffer, message.handles, 0);
548     int messageHeaderSize = decoder.readUint32();
549     payloadSize = message.buffer.lengthInBytes - messageHeaderSize;
551     int num_fields = decoder.readUint32();
552     name = decoder.readUint32();
553     flags = decoder.readUint32();
555     if (num_fields >= 3) {
556       requestID = decoder.readUint64();
557     }
558     decoder.skip(messageHeaderSize - decoder.next);
559   }
561   Object decodeStruct(Object t) => _callDecode(t, decoder);
565 abstract class MojoType<T> {
566   static const int encodedSize = 0;
567   static T decode(MojoDecoder decoder) { return null }
568   static void encode(MojoEncoder encoder, T val) {}
572 class PackedBool {}
575 class Int8 implements MojoType<int> {
576   static const int encodedSize = 1;
577   static int decode(MojoDecoder decoder) => decoder.readInt8();
578   static void encode(MojoEncoder encoder, int val) {
579     encoder.writeInt8(val);
580   }
584 class Uint8 implements MojoType<int> {
585   static const int encodedSize = 1;
586   static int decode(MojoDecoder decoder) => decoder.readUint8();
587   static void encode(MojoEncoder encoder, int val) {
588     encoder.writeUint8(val);
589   }
593 class Int16 implements MojoType<int> {
594   static const int encodedSize = 2;
595   static int decode(MojoDecoder decoder) => decoder.readInt16();
596   static void encode(MojoEncoder encoder, int val) {
597     encoder.writeInt16(val);
598   }
602 class Uint16 implements MojoType<int> {
603   static const int encodedSize = 2;
604   static int decode(MojoDecoder decoder) => decoder.readUint16();
605   static void encode(MojoEncoder encoder, int val) {
606     encoder.writeUint16(val);
607   }
611 class Int32 implements MojoType<int> {
612   static const int encodedSize = 4;
613   static int decode(MojoDecoder decoder) => decoder.readInt32();
614   static void encode(MojoEncoder encoder, int val) {
615     encoder.writeInt32(val);
616   }
620 class Uint32 implements MojoType<int> {
621   static const int encodedSize = 4;
622   static int decode(MojoDecoder decoder) => decoder.readUint32();
623   static void encode(MojoEncoder encoder, int val) {
624     encoder.writeUint32(val);
625   }
629 class Int64 implements MojoType<int> {
630   static const int encodedSize = 8;
631   static int decode(MojoDecoder decoder) => decoder.readInt64();
632   static void encode(MojoEncoder encoder, int val) {
633     encoder.writeInt64(val);
634   }
638 class Uint64 implements MojoType<int> {
639   static const int encodedSize = 8;
640   static int decode(MojoDecoder decoder) => decoder.readUint64();
641   static void encode(MojoEncoder encoder, int val) {
642     encoder.writeUint64(val);
643   }
647 class MojoString implements MojoType<String> {
648   static const int encodedSize = 8;
649   static String decode(MojoDecoder decoder) => decoder.decodeStringPointer();
650   static void encode(MojoEncoder encoder, String val) {
651     encoder.encodeStringPointer(val);
652   }
656 class NullableMojoString implements MojoType<String> {
657   static const int encodedSize = MojoString.encodedSize;
658   static var decode = MojoString.decode;
659   static var encode = MojoString.encode;
663 class Float implements MojoType<double> {
664   static const int encodedSize = 4;
665   static double decode(MojoDecoder decoder) => decoder.readFloat();
666   static void encode(MojoEncoder encoder, double val) {
667     encoder.writeFloat(val);
668   }
672 class Double implements MojoType<double> {
673   static const int encodedSize = 8;
674   static double decode(MojoDecoder decoder) => decoder.readDouble();
675   static void encode(MojoEncoder encoder, double val) {
676     encoder.writeDouble(val);
677   }
681 class PointerTo {
682   Object val;
684   PointerTo(this.val);
686   int encodedSize = 8;
687   Object decode(MojoDecoder decoder) {
688     int pointer = decoder.decodePointer();
689     if (pointer == 0) {
690       return null;
691     }
692     return _callDecode(val, decoder.decodeAndCreateDecoder(pointer));
693   }
694   void encode(MojoEncoder encoder, Object val) {
695     if (val == null) {
696       encoder.encodePointer(val);
697       return;
698     }
699     MojoEncoder obj_encoder =
700         encoder.createAndEncodeEncoder(getEncodedSize(this.val));
701     _callEncode(this.val, obj_encoder, val);
702   }
706 class NullablePointerTo extends PointerTo {
707   static const int encodedSize = PointerTo.encodedSize;
711 class ArrayOf {
712   Object val;
713   int length;
715   ArrayOf(this.val, [this.length = 0]);
717   int dimensions() => [length].addAll((val is ArrayOf) ? val.dimensions() : []);
719   int encodedSize = 8;
720   List decode(MojoDecoder decoder) => decoder.decodeArrayPointer(val);
721   void encode(MojoEncoder encoder, List val) {
722     encoder.encodeArrayPointer(this.val, val);
723   }
727 class NullableArrayOf extends ArrayOf {
728   static const int encodedSize = ArrayOf.encodedSize;
732 class Handle implements MojoType<int> {
733   static const int encodedSize = 4;
734   static int decode(MojoDecoder decoder) => decoder.decodeHandle();
735   static void encode(MojoEncoder encoder, int val) {
736     encoder.encodeHandle(val);
737   }
741 class NullableHandle implements MojoType<int> {
742   static const int encodedSize = Handle.encodedSize;
743   static const decode = Handle.decode;
744   static const encode = Handle.encode;