Chromium Code Reviews| Index: lib/isolate/serialization.dart |
| diff --git a/lib/isolate/serialization.dart b/lib/isolate/serialization.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..11e9ad9f43c16403a7e87b8a7b7f315ae958e22f |
| --- /dev/null |
| +++ b/lib/isolate/serialization.dart |
| @@ -0,0 +1,196 @@ |
| +// 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. |
| + |
| +class _MessageTraverserVisitedMap { |
| + |
| + operator[](var object) => null; |
|
vsm
2012/07/04 05:21:54
TODO to fill in?
|
| + 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); |
| + |
| + // TODO(floitsch): make this a real exception. (which one)? |
| + throw "Message serialization: Illegal value $x passed"; |
| + } |
| + |
| + abstract visitPrimitive(x); |
| + abstract visitList(List x); |
| + abstract visitMap(Map x); |
| + abstract visitSendPort(SendPort x); |
| + |
| + 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); |
| + // TODO(floitsch): Use real exception (which one?). |
| + default: throw "Unexpected serialized object"; |
| + } |
| + } |
| + |
| + _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); |
| + |
| +} |