| // 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. |
| |
| library utils; |
| |
| import 'dart-ext:dart_archive'; |
| import 'dart:isolate'; |
| import 'archive.dart' as archive; |
| |
| /** The cache of the port used to communicate with the C extension. */ |
| SendPort _port; |
| |
| /** The port used to communicate with the C extension. */ |
| SendPort get servicePort { |
| if (_port == null) _port = _newServicePort(); |
| return _port; |
| } |
| |
| /** Creates a new port to communicate with the C extension. */ |
| SendPort _newServicePort() native "Archive_ServicePort"; |
| |
| /** |
| * Send a message to the C extension. |
| * |
| * [requestType] is the specific request id to send. [id] is the id of the |
| * archive; it may be null for requests that don't operate on a specific |
| * archive. [args] are arguments that will be passed on to the extension. They |
| * should all be C-safe. |
| * |
| * Returns a future that completes with the C extension's reply. |
| */ |
| Future call(int requestType, [int id, List args]) { |
| var fullArgs = [requestType, id]; |
| if (args != null) fullArgs.addAll(args); |
| return servicePort.call(listForC(fullArgs)).transform((response) { |
| var success = response[0]; |
| var errno = response[1]; |
| var message = response[2]; |
| |
| if (!success) throw new ArchiveException(message, errno); |
| return message; |
| }); |
| } |
| |
| /** Converts [input] to a fixed-length list which C can understand. */ |
| List listForC(List input) { |
| var list = new List(input.length); |
| list.setRange(0, input.length, input); |
| return list; |
| } |
| |
| /** Converts [input] to a [Uint8List] that C can process easily. */ |
| Uint8List bytesForC(List<int> input) { |
| var list = new Uint8List(input.length); |
| list.setRange(0, input.length, input); |
| return list; |
| } |
| |
| /** |
| * Attaches [callback] as a finalizer for [object]. After [object] has been |
| * garbage collected, [callback] will be called and passed [peer] as an |
| * argument. |
| * |
| * Neither [callback] nor [peer] should contain any references to [object]; |
| * otherwise, [object] will never be collected and [callback] will never be |
| * called. |
| */ |
| void attachFinalizer(object, void callback(peer), [peer]) {} |
| |
| // TODO(nweiz): re-enable this once issue 4378 is fixed. |
| // void attachFinalizer(object, void callback(peer), [peer]) |
| // native "Archive_AttachFinalizer"; |
| |
| /** |
| * A reference to a single value. |
| * |
| * This is primarily meant to be used when a finalizer needs to refer to a field |
| * on the object being finalized that may be set to null during the lifetime of |
| * the object. Since the object itself has been garbage collected once the |
| * finalizer runs, it needs a second-order reference to check if the field is |
| * null. |
| */ |
| class Reference<E> { |
| E value; |
| Reference(this.value); |
| } |
| |
| /** |
| * Returns a [Future] that completes immediately upon hitting the event loop. |
| */ |
| Future async() { |
| var completer = new Completer(); |
| new Timer(0, (_) => completer.complete(null)); |
| return completer.future; |
| } |
| |
| /** An error raised by the archive library. */ |
| class ArchiveException implements archive.ArchiveException { |
| /** A description of the error that occurred. */ |
| final String message; |
| |
| /** The error code for the error, or null. */ |
| final int errno; |
| |
| ArchiveException(this.message, [this.errno]); |
| |
| String toString() { |
| if (errno == null) return "Archive error: $message"; |
| return "Archive error $errno: $message"; |
| } |
| } |