]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/issue-2718.rs
switch Drop to `&mut self`
[rust.git] / src / test / run-pass / issue-2718.rs
1 // xfail-fast
2
3 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
4 // file at the top-level directory of this distribution and at
5 // http://rust-lang.org/COPYRIGHT.
6 //
7 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10 // option. This file may not be copied, modified, or distributed
11 // except according to those terms.
12
13 pub type Task = int;
14
15 // tjc: I don't know why
16 pub mod pipes {
17     use super::Task;
18     use std::cast::{forget, transmute};
19     use std::cast;
20     use std::task;
21     use std::util;
22
23     pub struct Stuff<T> {
24         state: state,
25         blocked_task: Option<Task>,
26         payload: Option<T>
27     }
28
29     #[deriving(Eq)]
30     pub enum state {
31         empty,
32         full,
33         blocked,
34         terminated
35     }
36
37     pub struct packet<T> {
38         state: state,
39         blocked_task: Option<Task>,
40         payload: Option<T>
41     }
42
43     pub fn packet<T:Send>() -> *packet<T> {
44         unsafe {
45             let p: *packet<T> = cast::transmute(~Stuff{
46                 state: empty,
47                 blocked_task: None::<Task>,
48                 payload: None::<T>
49             });
50             p
51         }
52     }
53
54     mod rusti {
55       pub fn atomic_xchg(_dst: &mut int, _src: int) -> int { fail!(); }
56       pub fn atomic_xchg_acq(_dst: &mut int, _src: int) -> int { fail!(); }
57       pub fn atomic_xchg_rel(_dst: &mut int, _src: int) -> int { fail!(); }
58     }
59
60     // We should consider moving this to ::std::unsafe, although I
61     // suspect graydon would want us to use void pointers instead.
62     pub unsafe fn uniquify<T>(x: *T) -> ~T {
63         cast::transmute(x)
64     }
65
66     pub fn swap_state_acq(dst: &mut state, src: state) -> state {
67         unsafe {
68             transmute(rusti::atomic_xchg_acq(transmute(dst), src as int))
69         }
70     }
71
72     pub fn swap_state_rel(dst: &mut state, src: state) -> state {
73         unsafe {
74             transmute(rusti::atomic_xchg_rel(transmute(dst), src as int))
75         }
76     }
77
78     pub fn send<T:Send>(mut p: send_packet<T>, payload: T) {
79         let p = p.unwrap();
80         let mut p = unsafe { uniquify(p) };
81         assert!((*p).payload.is_none());
82         (*p).payload = Some(payload);
83         let old_state = swap_state_rel(&mut (*p).state, full);
84         match old_state {
85           empty => {
86             // Yay, fastpath.
87
88             // The receiver will eventually clean this up.
89             unsafe { forget(p); }
90           }
91           full => { fail!("duplicate send") }
92           blocked => {
93
94             // The receiver will eventually clean this up.
95             unsafe { forget(p); }
96           }
97           terminated => {
98             // The receiver will never receive this. Rely on drop_glue
99             // to clean everything up.
100           }
101         }
102     }
103
104     pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> {
105         let p = p.unwrap();
106         let mut p = unsafe { uniquify(p) };
107         loop {
108             let old_state = swap_state_acq(&mut (*p).state,
109                                            blocked);
110             match old_state {
111               empty | blocked => { task::deschedule(); }
112               full => {
113                 let payload = util::replace(&mut p.payload, None);
114                 return Some(payload.unwrap())
115               }
116               terminated => {
117                 assert_eq!(old_state, terminated);
118                 return None;
119               }
120             }
121         }
122     }
123
124     pub fn sender_terminate<T:Send>(p: *packet<T>) {
125         let mut p = unsafe { uniquify(p) };
126         match swap_state_rel(&mut (*p).state, terminated) {
127           empty | blocked => {
128             // The receiver will eventually clean up.
129             unsafe { forget(p) }
130           }
131           full => {
132             // This is impossible
133             fail!("you dun goofed")
134           }
135           terminated => {
136             // I have to clean up, use drop_glue
137           }
138         }
139     }
140
141     pub fn receiver_terminate<T:Send>(p: *packet<T>) {
142         let mut p = unsafe { uniquify(p) };
143         match swap_state_rel(&mut (*p).state, terminated) {
144           empty => {
145             // the sender will clean up
146             unsafe { forget(p) }
147           }
148           blocked => {
149             // this shouldn't happen.
150             fail!("terminating a blocked packet")
151           }
152           terminated | full => {
153             // I have to clean up, use drop_glue
154           }
155         }
156     }
157
158     pub struct send_packet<T> {
159         p: Option<*packet<T>>,
160     }
161
162     #[unsafe_destructor]
163     impl<T:Send> Drop for send_packet<T> {
164         fn drop(&mut self) {
165             unsafe {
166                 if self.p != None {
167                     let self_p: &mut Option<*packet<T>> =
168                         cast::transmute(&self.p);
169                     let p = util::replace(self_p, None);
170                     sender_terminate(p.unwrap())
171                 }
172             }
173         }
174     }
175
176     impl<T:Send> send_packet<T> {
177         pub fn unwrap(&mut self) -> *packet<T> {
178             util::replace(&mut self.p, None).unwrap()
179         }
180     }
181
182     pub fn send_packet<T:Send>(p: *packet<T>) -> send_packet<T> {
183         send_packet {
184             p: Some(p)
185         }
186     }
187
188     pub struct recv_packet<T> {
189         p: Option<*packet<T>>,
190     }
191
192     #[unsafe_destructor]
193     impl<T:Send> Drop for recv_packet<T> {
194         fn drop(&mut self) {
195             unsafe {
196                 if self.p != None {
197                     let self_p: &mut Option<*packet<T>> =
198                         cast::transmute(&self.p);
199                     let p = util::replace(self_p, None);
200                     receiver_terminate(p.unwrap())
201                 }
202             }
203         }
204     }
205
206     impl<T:Send> recv_packet<T> {
207         pub fn unwrap(&mut self) -> *packet<T> {
208             util::replace(&mut self.p, None).unwrap()
209         }
210     }
211
212     pub fn recv_packet<T:Send>(p: *packet<T>) -> recv_packet<T> {
213         recv_packet {
214             p: Some(p)
215         }
216     }
217
218     pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) {
219         let p = packet();
220         (send_packet(p), recv_packet(p))
221     }
222 }
223
224 pub mod pingpong {
225     use std::cast;
226
227     pub struct ping(::pipes::send_packet<pong>);
228     pub struct pong(::pipes::send_packet<ping>);
229
230     pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
231         unsafe {
232             let _addr : *::pipes::send_packet<pong> = match &p {
233               &ping(ref x) => { cast::transmute(x) }
234             };
235             fail!()
236         }
237     }
238
239     pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> {
240         unsafe {
241             let _addr : *::pipes::send_packet<ping> = match &p {
242               &pong(ref x) => { cast::transmute(x) }
243             };
244             fail!()
245         }
246     }
247
248     pub fn init() -> (client::ping, server::ping) {
249         ::pipes::entangle()
250     }
251
252     pub mod client {
253         use pingpong;
254
255         pub type ping = ::pipes::send_packet<pingpong::ping>;
256         pub type pong = ::pipes::recv_packet<pingpong::pong>;
257
258         pub fn do_ping(c: ping) -> pong {
259             let (sp, rp) = ::pipes::entangle();
260
261             ::pipes::send(c, pingpong::ping(sp));
262             rp
263         }
264
265         pub fn do_pong(c: pong) -> (ping, ()) {
266             let packet = ::pipes::recv(c);
267             if packet.is_none() {
268                 fail!("sender closed the connection")
269             }
270             (pingpong::liberate_pong(packet.unwrap()), ())
271         }
272     }
273
274     pub mod server {
275         use pingpong;
276
277         pub type ping = ::pipes::recv_packet<pingpong::ping>;
278         pub type pong = ::pipes::send_packet<pingpong::pong>;
279
280         pub fn do_ping(c: ping) -> (pong, ()) {
281             let packet = ::pipes::recv(c);
282             if packet.is_none() {
283                 fail!("sender closed the connection")
284             }
285             (pingpong::liberate_ping(packet.unwrap()), ())
286         }
287
288         pub fn do_pong(c: pong) -> ping {
289             let (sp, rp) = ::pipes::entangle();
290             ::pipes::send(c, pingpong::pong(sp));
291             rp
292         }
293     }
294 }
295
296 fn client(chan: pingpong::client::ping) {
297     let chan = pingpong::client::do_ping(chan);
298     error!(~"Sent ping");
299     let (_chan, _data) = pingpong::client::do_pong(chan);
300     error!(~"Received pong");
301 }
302
303 fn server(chan: pingpong::server::ping) {
304     let (chan, _data) = pingpong::server::do_ping(chan);
305     error!(~"Received ping");
306     let _chan = pingpong::server::do_pong(chan);
307     error!(~"Sent pong");
308 }
309
310 pub fn main() {
311   /*
312 //    Commented out because of option::get error
313
314     let (client_, server_) = pingpong::init();
315     let client_ = Cell::new(client_);
316     let server_ = Cell::new(server_);
317
318     task::spawn {|client_|
319         let client__ = client_.take();
320         client(client__);
321     };
322     task::spawn {|server_|
323         let server__ = server_.take();
324         server(server_ˊ);
325     };
326   */
327 }