|  | // 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<SendPort> completer = new Completer<SendPort>(); | 
|  | SendPort replyPort = singleMessagePort(callback); | 
|  | late 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]; | 
|  | late 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<SendPort> 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<void>((v) => throw "allowed spawn direct?", onError: (e, s) { | 
|  | asyncEnd(); | 
|  | }); | 
|  | asyncStart(); | 
|  | Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], [func]) | 
|  | .then<void>((v) => throw "allowed spawn wrapped?", onError: (e, s) { | 
|  | asyncEnd(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void callFunc(message) { | 
|  | message[0](message[1], message[2]); | 
|  | } |