|  | // Copyright (c) 2015, 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. | 
|  |  | 
|  | import "dart:isolate"; | 
|  | import "dart:async"; | 
|  | import "package:expect/expect.dart"; | 
|  | import "package:async_helper/async_helper.dart"; | 
|  |  | 
|  | void toplevel(port, message) { port.send("toplevel:$message"); } | 
|  | Function createFuncToplevel() => (p, m) { p.send(m); }; | 
|  | class C { | 
|  | Function initializer; | 
|  | Function body; | 
|  | C() : initializer = ((p, m) { throw "initializer"; }) { | 
|  | body = (p, m) { throw "body"; }; | 
|  | } | 
|  | static void staticFunc(port, message) { port.send("static:$message"); } | 
|  | static Function createFuncStatic() => (p, m) { throw "static expr"; }; | 
|  | void instanceMethod(p, m) { throw "instanceMethod"; } | 
|  | Function createFuncMember() => (p, m) { throw "instance expr"; }; | 
|  | void call(n, p) { throw "C"; } | 
|  | } | 
|  |  | 
|  | class Callable { | 
|  | void call(p, m) { p.send(["callable", m]); } | 
|  | } | 
|  |  | 
|  |  | 
|  | void main() { | 
|  | asyncStart(); | 
|  |  | 
|  | // top-level functions, static functions, closures, instance methods | 
|  | // or function expressions are not sendable to an isolate spawned using | 
|  | // spawnUri. | 
|  | testUnsendable("toplevel", toplevel); | 
|  | testUnsendable("static", C.staticFunc); | 
|  | var c = new C(); | 
|  | testUnsendable("instance method", c.instanceMethod); | 
|  | testUnsendable("static context expression", createFuncToplevel()); | 
|  | testUnsendable("static context expression", C.createFuncStatic()); | 
|  | testUnsendable("initializer context expression", c.initializer); | 
|  | testUnsendable("constructor context expression", c.body); | 
|  | testUnsendable("instance method context expression", c.createFuncMember()); | 
|  | testUnsendable("toplevel", toplevel.call); | 
|  | testUnsendable("static", C.staticFunc.call); | 
|  | testUnsendable("callable object", new Callable().call); | 
|  |  | 
|  | asyncEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Create a receive port that expects exactly one message. | 
|  | // Pass the message to `callback` and return the sendPort. | 
|  | SendPort singleMessagePort(callback) { | 
|  | var p; | 
|  | p = new RawReceivePort((v) { p.close(); callback(v); }); | 
|  | return p.sendPort; | 
|  | } | 
|  |  | 
|  | // A singleMessagePort that expects the message to be a specific value. | 
|  | SendPort expectMessagePort(message) { | 
|  | asyncStart(); | 
|  | return singleMessagePort((v) { | 
|  | Expect.equals(message, v); | 
|  | asyncEnd(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Creates a new isolate and a pair of ports that expect a single message | 
|  | // to be sent to the other isolate and back to the callback function. | 
|  | Future<SendPort> echoPort(callback(value)) { | 
|  | Completer completer = new Completer<SendPort>(); | 
|  | SendPort replyPort = singleMessagePort(callback); | 
|  | RawReceivePort initPort; | 
|  | initPort = new RawReceivePort((p) { | 
|  | completer.complete(p); | 
|  | initPort.close(); | 
|  | }); | 
|  | return Isolate.spawn(_echo, [replyPort, initPort.sendPort]) | 
|  | .then((isolate) => completer.future); | 
|  | } | 
|  |  | 
|  | void _echo(msg) { | 
|  | var replyPort = msg[0]; | 
|  | RawReceivePort requestPort; | 
|  | requestPort = new RawReceivePort((msg) { | 
|  | replyPort.send(msg); | 
|  | requestPort.close();  // Single echo only. | 
|  | }); | 
|  | msg[1].send(requestPort.sendPort); | 
|  | } | 
|  |  | 
|  | // Creates other isolate that waits for a single message, `msg`, on the returned | 
|  | // port, and executes it as `msg[0](msg[1],msg[2])` in the other isolate. | 
|  | Future<SendPort> callPort() { | 
|  | Completer completer = new Completer<SendPort>(); | 
|  | SendPort initPort = singleMessagePort(completer.complete); | 
|  | return Isolate.spawn(_call, initPort) | 
|  | .then((_) => completer.future); | 
|  | } | 
|  |  | 
|  | void _call(initPort) { | 
|  | initPort.send(singleMessagePort(callFunc)); | 
|  | } | 
|  |  | 
|  | void testUnsendable(name, func) { | 
|  | asyncStart(); | 
|  | Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], func) | 
|  | .then((v) => throw "allowed spawn direct?", onError: (e,s){ asyncEnd(); }); | 
|  | asyncStart(); | 
|  | Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], [func]) | 
|  | .then((v) => throw "allowed spawn wrapped?", onError: (e,s){ asyncEnd(); }); | 
|  | } | 
|  |  | 
|  | void callFunc(message) { | 
|  | message[0](message[1], message[2]); | 
|  | } |