| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| // Patch file for the dart:isolate library. | |
| /******************************************************** | |
| Inserted from lib/isolate/serialization.dart | |
| ********************************************************/ | |
| class _MessageTraverserVisitedMap { | |
| operator[](var object) => null; | |
| void operator[]=(var object, var info) { } | |
| void reset() { } | |
| void cleanup() { } | |
| } | |
| /** Abstract visitor for dart objects that can be sent as isolate messages. */ | |
| class _MessageTraverser { | |
| _MessageTraverserVisitedMap _visited; | |
| _MessageTraverser() : _visited = new _MessageTraverserVisitedMap(); | |
| /** Visitor's entry point. */ | |
| traverse(var x) { | |
| if (isPrimitive(x)) return visitPrimitive(x); | |
| _visited.reset(); | |
| var result; | |
| try { | |
| result = _dispatch(x); | |
| } finally { | |
| _visited.cleanup(); | |
| } | |
| return result; | |
| } | |
| _dispatch(var x) { | |
| if (isPrimitive(x)) return visitPrimitive(x); | |
| if (x is List) return visitList(x); | |
| if (x is Map) return visitMap(x); | |
| if (x is SendPort) return visitSendPort(x); | |
| if (x is SendPortSync) return visitSendPortSync(x); | |
| // Overridable fallback. | |
| return visitObject(x); | |
| } | |
| abstract visitPrimitive(x); | |
| abstract visitList(List x); | |
| abstract visitMap(Map x); | |
| abstract visitSendPort(SendPort x); | |
| abstract visitSendPortSync(SendPortSync x); | |
| visitObject(Object x) { | |
| // TODO(floitsch): make this a real exception. (which one)? | |
| throw "Message serialization: Illegal value $x passed"; | |
| } | |
| static bool isPrimitive(x) { | |
| return (x === null) || (x is String) || (x is num) || (x is bool); | |
| } | |
| } | |
| /** A visitor that recursively copies a message. */ | |
| class _Copier extends _MessageTraverser { | |
| visitPrimitive(x) => x; | |
| List visitList(List list) { | |
| List copy = _visited[list]; | |
| if (copy !== null) return copy; | |
| int len = list.length; | |
| // TODO(floitsch): we loose the generic type of the List. | |
| copy = new List(len); | |
| _visited[list] = copy; | |
| for (int i = 0; i < len; i++) { | |
| copy[i] = _dispatch(list[i]); | |
| } | |
| return copy; | |
| } | |
| Map visitMap(Map map) { | |
| Map copy = _visited[map]; | |
| if (copy !== null) return copy; | |
| // TODO(floitsch): we loose the generic type of the map. | |
| copy = new Map(); | |
| _visited[map] = copy; | |
| map.forEach((key, val) { | |
| copy[_dispatch(key)] = _dispatch(val); | |
| }); | |
| return copy; | |
| } | |
| } | |
| /** Visitor that serializes a message as a JSON array. */ | |
| class _Serializer extends _MessageTraverser { | |
| int _nextFreeRefId = 0; | |
| visitPrimitive(x) => x; | |
| visitList(List list) { | |
| int copyId = _visited[list]; | |
| if (copyId !== null) return ['ref', copyId]; | |
| int id = _nextFreeRefId++; | |
| _visited[list] = id; | |
| var jsArray = _serializeList(list); | |
| // TODO(floitsch): we are losing the generic type. | |
| return ['list', id, jsArray]; | |
| } | |
| visitMap(Map map) { | |
| int copyId = _visited[map]; | |
| if (copyId !== null) return ['ref', copyId]; | |
| int id = _nextFreeRefId++; | |
| _visited[map] = id; | |
| var keys = _serializeList(map.getKeys()); | |
| var values = _serializeList(map.getValues()); | |
| // TODO(floitsch): we are losing the generic type. | |
| return ['map', id, keys, values]; | |
| } | |
| _serializeList(List list) { | |
| int len = list.length; | |
| var result = new List(len); | |
| for (int i = 0; i < len; i++) { | |
| result[i] = _dispatch(list[i]); | |
| } | |
| return result; | |
| } | |
| } | |
| /** Deserializes arrays created with [_Serializer]. */ | |
| class _Deserializer { | |
| Map<int, Dynamic> _deserialized; | |
| _Deserializer(); | |
| static bool isPrimitive(x) { | |
| return (x === null) || (x is String) || (x is num) || (x is bool); | |
| } | |
| deserialize(x) { | |
| if (isPrimitive(x)) return x; | |
| // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() | |
| _deserialized = new HashMap(); | |
| return _deserializeHelper(x); | |
| } | |
| _deserializeHelper(x) { | |
| if (isPrimitive(x)) return x; | |
| assert(x is List); | |
| switch (x[0]) { | |
| case 'ref': return _deserializeRef(x); | |
| case 'list': return _deserializeList(x); | |
| case 'map': return _deserializeMap(x); | |
| case 'sendport': return deserializeSendPort(x); | |
| default: return deserializeObject(x); | |
| } | |
| } | |
| _deserializeRef(List x) { | |
| int id = x[1]; | |
| var result = _deserialized[id]; | |
| assert(result !== null); | |
| return result; | |
| } | |
| List _deserializeList(List x) { | |
| int id = x[1]; | |
| // We rely on the fact that Dart-lists are directly mapped to Js-arrays. | |
| List dartList = x[2]; | |
| _deserialized[id] = dartList; | |
| int len = dartList.length; | |
| for (int i = 0; i < len; i++) { | |
| dartList[i] = _deserializeHelper(dartList[i]); | |
| } | |
| return dartList; | |
| } | |
| Map _deserializeMap(List x) { | |
| Map result = new Map(); | |
| int id = x[1]; | |
| _deserialized[id] = result; | |
| List keys = x[2]; | |
| List values = x[3]; | |
| int len = keys.length; | |
| assert(len == values.length); | |
| for (int i = 0; i < len; i++) { | |
| var key = _deserializeHelper(keys[i]); | |
| var value = _deserializeHelper(values[i]); | |
| result[key] = value; | |
| } | |
| return result; | |
| } | |
| abstract deserializeSendPort(List x); | |
| deserializeObject(List x) { | |
| // TODO(floitsch): Use real exception (which one?). | |
| throw "Unexpected serialized object"; | |
| } | |
| } | |