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