OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // Things that should be "auto-generated" are between AUTO START and | |
6 // AUTO END (or just AUTO if it's a single line). | |
7 | |
8 library MintMakerTest; | 5 library MintMakerTest; |
9 import 'dart:isolate'; | 6 import 'dart:isolate'; |
10 import '../../pkg/unittest/lib/unittest.dart'; | 7 import '../../pkg/unittest/lib/unittest.dart'; |
11 | 8 |
12 class Mint { | 9 class Mint { |
13 Mint() : registry_ = new Map<SendPort, Purse>() { | 10 Map<SendPort, Purse> _registry; |
14 // AUTO START | 11 SendPort port; |
| 12 |
| 13 Mint() : _registry = new Map<SendPort, Purse>() { |
15 ReceivePort mintPort = new ReceivePort(); | 14 ReceivePort mintPort = new ReceivePort(); |
16 port = mintPort.toSendPort(); | 15 port = mintPort.sendPort; |
17 serveMint(mintPort); | 16 serveMint(mintPort); |
18 // AUTO END | |
19 } | 17 } |
20 | 18 |
21 // AUTO START | |
22 void serveMint(ReceivePort port) { | 19 void serveMint(ReceivePort port) { |
23 port.receive((var message, SendPort replyTo) { | 20 port.listen((message) { |
24 int balance = message; | 21 int balance = message[0]; |
25 Purse purse = createPurse(balance); | 22 Purse purse = createPurse(balance); |
26 replyTo.send([ purse.port ], null); | 23 message[1].send(purse.port); |
27 }); | 24 }); |
28 } | 25 } |
29 // AUTO END | |
30 | 26 |
31 Purse createPurse(int balance) { | 27 Purse createPurse(int balance) { |
32 Purse purse = new Purse(this, balance); | 28 Purse purse = new Purse(this, balance); |
33 registry_[purse.port] = purse; | 29 _registry[purse.port] = purse; |
34 return purse; | 30 return purse; |
35 } | 31 } |
36 | 32 |
37 Purse lookupPurse(SendPort port) { | 33 Purse lookupPurse(SendPort port) { |
38 return registry_[port]; | 34 return _registry[port]; |
39 } | 35 } |
40 | |
41 Map<SendPort, Purse> registry_; | |
42 // AUTO | |
43 SendPort port; | |
44 } | 36 } |
45 | 37 |
46 | 38 |
47 // AUTO START | |
48 class MintWrapper { | 39 class MintWrapper { |
49 MintWrapper(SendPort this.mint_) {} | 40 SendPort _mint; |
| 41 MintWrapper(SendPort this._mint) {} |
50 | 42 |
51 void createPurse(int balance, handlePurse(PurseWrapper purse)) { | 43 void createPurse(int balance, handlePurse(PurseWrapper purse)) { |
52 mint_.call(balance).then((var message) { | 44 ReceivePort reply = new ReceivePort(); |
53 SendPort purse = message[0]; | 45 reply.first.then((SendPort purse) { |
54 handlePurse(new PurseWrapper(purse)); | 46 handlePurse(new PurseWrapper(purse)); |
55 }); | 47 }); |
| 48 _mint.send([balance, reply.sendPort]); |
56 } | 49 } |
57 | 50 |
58 SendPort mint_; | |
59 } | 51 } |
60 // AUTO END | |
61 | 52 |
| 53 class Purse { |
| 54 Mint mint; |
| 55 int balance; |
| 56 SendPort port; |
62 | 57 |
63 /* | 58 Purse(this.mint, this.balance) { |
64 One way this could look without the autogenerated code: | 59 ReceivePort recipient = new ReceivePort(); |
65 | 60 port = recipient.sendPort; |
66 class Mint { | 61 servePurse(recipient); |
67 Mint() : registry_ = new Map<SendPort, Purse>() { | |
68 } | 62 } |
69 | 63 |
70 wrap Purse createPurse(int balance) { | |
71 Purse purse = new Purse(this, balance); | |
72 registry_[purse.port] = purse; | |
73 return purse; | |
74 } | |
75 | |
76 Purse lookupPurse(SendPort port) { | |
77 return registry_[port]; | |
78 } | |
79 | |
80 Map<SendPort, Purse> registry_; | |
81 } | |
82 | |
83 The other end of the port would use Wrapper<Mint> as the wrapper, or | |
84 Future<Mint> as a future for the wrapper. | |
85 */ | |
86 | |
87 | |
88 class Purse { | |
89 Purse(Mint this.mint, int this.balance) { | |
90 // AUTO START | |
91 ReceivePort recipient = new ReceivePort(); | |
92 port = recipient.toSendPort(); | |
93 servePurse(recipient); | |
94 // AUTO END | |
95 } | |
96 | |
97 // AUTO START | |
98 void servePurse(ReceivePort recipient) { | 64 void servePurse(ReceivePort recipient) { |
99 recipient.receive((var message, SendPort replyTo) { | 65 recipient.listen((message) { |
100 String command = message[0]; | 66 String command = message[0]; |
101 if (command == "balance") { | 67 if (command == "balance") { |
102 replyTo.send(queryBalance(), null); | 68 SendPort replyTo = message.last; |
| 69 replyTo.send(queryBalance()); |
103 } else if (command == "deposit") { | 70 } else if (command == "deposit") { |
104 Purse source = mint.lookupPurse(message[2]); | 71 Purse source = mint.lookupPurse(message[2]); |
105 deposit(message[1], source); | 72 deposit(message[1], source); |
106 } else if (command == "sprout") { | 73 } else if (command == "sprout") { |
| 74 SendPort replyTo = message.last; |
107 Purse result = sproutPurse(); | 75 Purse result = sproutPurse(); |
108 replyTo.send([ result.port ], null); | 76 replyTo.send(result.port); |
109 } else { | 77 } else { |
110 // TODO: Send an exception back. | 78 // TODO: Send an exception back. |
111 replyTo.send("Exception: Command not understood", null); | 79 throw UnsupportedError("Unsupported commend: $command"); |
112 } | 80 } |
113 }); | 81 }); |
114 } | 82 } |
115 // AUTO END | |
116 | 83 |
117 int queryBalance() { return balance; } | 84 int queryBalance() { return balance; } |
118 | 85 |
119 Purse sproutPurse() { return mint.createPurse(0); } | 86 Purse sproutPurse() { return mint.createPurse(0); } |
120 | 87 |
121 void deposit(int amount, Purse source) { | 88 void deposit(int amount, Purse source) { |
122 // TODO: Throw an exception if the source purse doesn't hold | 89 // TODO: Throw an exception if the source purse doesn't hold |
123 // enough dough. | 90 // enough dough. |
124 balance += amount; | 91 balance += amount; |
125 source.balance -= amount; | 92 source.balance -= amount; |
126 } | 93 } |
127 | |
128 Mint mint; | |
129 int balance; | |
130 // AUTO | |
131 SendPort port; | |
132 } | 94 } |
133 | 95 |
134 | 96 |
135 // AUTO START | |
136 class PurseWrapper { | 97 class PurseWrapper { |
137 PurseWrapper(SendPort this.purse_) {} | 98 SendPort _purse; |
| 99 |
| 100 PurseWrapper(this._purse) {} |
| 101 |
| 102 void _sendReceive(message, replyHandler(reply)) { |
| 103 ReceivePort reply = new ReceivePort(); |
| 104 _purse.send([message, reply.sendPort]); |
| 105 reply.first.then(replyHandler); |
| 106 } |
138 | 107 |
139 void queryBalance(handleBalance(int balance)) { | 108 void queryBalance(handleBalance(int balance)) { |
140 purse_.call([ "balance" ]).then((var message) { | 109 _sendReceive("balance", handleBalance); |
141 int balance = message; | |
142 handleBalance(balance); | |
143 }); | |
144 } | 110 } |
145 | 111 |
146 void sproutPurse(handleSprouted(PurseWrapper sprouted)) { | 112 void sproutPurse(handleSprouted(PurseWrapper sprouted)) { |
147 purse_.call([ "sprout" ]).then((var message) { | 113 _sendReceive("sprout", (SendPort sprouted) { |
148 SendPort sprouted = message[0]; | |
149 handleSprouted(new PurseWrapper(sprouted)); | 114 handleSprouted(new PurseWrapper(sprouted)); |
150 }); | 115 }); |
151 } | 116 } |
152 | 117 |
153 void deposit(PurseWrapper source, int amount) { | 118 void deposit(PurseWrapper source, int amount) { |
154 purse_.send([ "deposit", amount, source.purse_ ], null); | 119 _purse.send([ "deposit", amount, source._purse ]); |
155 } | 120 } |
| 121 } |
156 | 122 |
157 | 123 mintMakerWrapper(SendPort replyPort) { |
158 SendPort purse_; | 124 ReceivePort receiver = new ReceivePort(); |
159 } | 125 replyPort.send(receiver.sendPort); |
160 // AUTO END | 126 receiver.listen((SendPort replyTo) { |
161 | |
162 | |
163 // AUTO STATUS UNCLEAR! | |
164 | |
165 mintMakerWrapper() { | |
166 port.receive((var message, SendPort replyTo) { | |
167 Mint mint = new Mint(); | 127 Mint mint = new Mint(); |
168 replyTo.send([ mint.port ], null); | 128 replyTo.send(mint.port); |
169 }); | 129 }); |
170 } | 130 } |
171 | 131 |
172 class MintMakerWrapper { | 132 class MintMakerWrapper { |
173 MintMakerWrapper() { | 133 final SendPort _port; |
174 port_ = spawnFunction(mintMakerWrapper); | 134 |
| 135 static Future<MintMakerWrapper> create() { |
| 136 ReceivePort reply = new ReceivePort(); |
| 137 return Isolate.spawn(mintMakerWrapper, reply.sendPort).then((_) => |
| 138 reply.first.then((port) => new MintMakerWrapper._(port))); |
175 } | 139 } |
176 | 140 |
| 141 MintMakerWrapper._(this._port); |
| 142 |
177 void makeMint(handleMint(MintWrapper mint)) { | 143 void makeMint(handleMint(MintWrapper mint)) { |
178 port_.call(null).then((var message) { | 144 ReceivePort reply = new ReceivePort(); |
179 SendPort mint = message[0]; | 145 reply.first.then((SendPort mint) { handleMint(new MintWrapper(mint)); }); |
180 handleMint(new MintWrapper(mint)); | 146 _port.send(reply.sendPort); |
181 }); | |
182 } | 147 } |
183 | |
184 SendPort port_; | |
185 } | 148 } |
186 | 149 |
187 _checkBalance(PurseWrapper wrapper, expected) { | 150 _checkBalance(PurseWrapper wrapper, expected) { |
188 wrapper.queryBalance(expectAsync1((int balance) { | 151 wrapper.queryBalance(expectAsync1((int balance) { |
189 expect(balance, equals(expected)); | 152 expect(balance, equals(expected)); |
190 })); | 153 })); |
191 } | 154 } |
192 | 155 |
193 main() { | 156 main() { |
194 test("creating purse, deposit, and query balance", () { | 157 test("creating purse, deposit, and query balance", () { |
195 MintMakerWrapper mintMaker = new MintMakerWrapper(); | 158 MintMakerWrapper.create().then(expectAsync1((mintMaker) { |
196 mintMaker.makeMint(expectAsync1((MintWrapper mint) { | 159 mintMaker.makeMint(expectAsync1((MintWrapper mint) { |
197 mint.createPurse(100, expectAsync1((PurseWrapper purse) { | 160 mint.createPurse(100, expectAsync1((PurseWrapper purse) { |
198 _checkBalance(purse, 100); | |
199 purse.sproutPurse(expectAsync1((PurseWrapper sprouted) { | |
200 _checkBalance(sprouted, 0); | |
201 _checkBalance(purse, 100); | 161 _checkBalance(purse, 100); |
| 162 purse.sproutPurse(expectAsync1((PurseWrapper sprouted) { |
| 163 _checkBalance(sprouted, 0); |
| 164 _checkBalance(purse, 100); |
202 | 165 |
203 sprouted.deposit(purse, 5); | 166 sprouted.deposit(purse, 5); |
204 _checkBalance(sprouted, 0 + 5); | 167 _checkBalance(sprouted, 0 + 5); |
205 _checkBalance(purse, 100 - 5); | 168 _checkBalance(purse, 100 - 5); |
206 | 169 |
207 sprouted.deposit(purse, 42); | 170 sprouted.deposit(purse, 42); |
208 _checkBalance(sprouted, 0 + 5 + 42); | 171 _checkBalance(sprouted, 0 + 5 + 42); |
209 _checkBalance(purse, 100 - 5 - 42); | 172 _checkBalance(purse, 100 - 5 - 42); |
| 173 })); |
210 })); | 174 })); |
211 })); | 175 })); |
212 })); | 176 })); |
213 }); | 177 }); |
214 | |
215 /* This is an attempt to show how the above code could look like if we had | |
216 * better language support for asynchronous messages (deferred/asynccall). | |
217 * The static helper methods like createPurse and queryBalance would also | |
218 * have to be marked async. | |
219 | |
220 void run(port) { | |
221 MintMakerWrapper mintMaker = spawnMintMaker(); | |
222 deferred { | |
223 MintWrapper mint = asynccall mintMaker.createMint(); | |
224 PurseWrapper purse = asynccall mint.createPurse(100); | |
225 expect(asynccall purse.queryBalance(), 100); | |
226 | |
227 PurseWrapper sprouted = asynccall purse.sproutPurse(); | |
228 expect(asynccall sprouted.queryBalance(), 0); | |
229 | |
230 asynccall sprouted.deposit(purse, 5); | |
231 expect(asynccall sprouted.queryBalance(), 0 + 5); | |
232 expect(asynccall purse.queryBalance(), 100 - 5); | |
233 | |
234 asynccall sprouted.deposit(purse, 42); | |
235 expect(asynccall sprouted.queryBalance(), 0 + 5 + 42); | |
236 expect(asynccall purse.queryBalance(), 100 - 5 - 42); | |
237 } | |
238 } | |
239 */ | |
240 | |
241 /* And a version using futures and wrappers. | |
242 | |
243 void run(port) { | |
244 Wrapper<MintMaker> mintMaker = spawnMintMaker(); | |
245 Future<Mint> mint = mintMaker...createMint(); | |
246 Future<Purse> purse = mint...createPurse(100); | |
247 expect(purse.queryBalance(), 100); | |
248 | |
249 Future<Purse> sprouted = purse...sproutPurse(); | |
250 expect(0, sprouted.queryBalance()); | |
251 | |
252 sprouted...deposit(purse, 5); | |
253 expect(sprouted.queryBalance(), 0 + 5); | |
254 expect(purse.queryBalance(), 100 - 5); | |
255 | |
256 sprouted...deposit(purse, 42); | |
257 expect(sprouted.queryBalance(), 0 + 5 + 42); | |
258 expect(purse.queryBalance(), 100 - 5 - 42); | |
259 } | |
260 */ | |
261 } | 178 } |
OLD | NEW |