about summary refs log tree commit diff
path: root/src/libstd/comm/select.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/comm/select.rs')
-rw-r--r--src/libstd/comm/select.rs120
1 files changed, 106 insertions, 14 deletions
diff --git a/src/libstd/comm/select.rs b/src/libstd/comm/select.rs
index b6b35ccc357..e41fa60aa42 100644
--- a/src/libstd/comm/select.rs
+++ b/src/libstd/comm/select.rs
@@ -60,21 +60,17 @@ use uint;
 
 macro_rules! select {
     (
-        $name1:pat = $port1:ident.$meth1:ident() => $code1:expr,
-        $($name:pat = $port:ident.$meth:ident() => $code:expr),*
+        $($name:pat = $port:ident.$meth:ident() => $code:expr),+
     ) => ({
         use std::comm::Select;
         let sel = Select::new();
-        let mut $port1 = sel.handle(&$port1);
-        $( let mut $port = sel.handle(&$port); )*
+        $( let mut $port = sel.handle(&$port); )+
         unsafe {
-            $port1.add();
-            $( $port.add(); )*
+            $( $port.add(); )+
         }
         let ret = sel.wait();
-        if ret == $port1.id { let $name1 = $port1.$meth1(); $code1 }
-        $( else if ret == $port.id { let $name = $port.$meth(); $code } )*
-        else { unreachable!() }
+        $( if ret == $port.id() { let $name = $port.$meth(); $code } else )+
+        { unreachable!() }
     })
 }
 
@@ -94,7 +90,7 @@ pub struct Select {
 pub struct Handle<'port, T> {
     /// The ID of this handle, used to compare against the return value of
     /// `Select::wait()`
-    id: uint,
+    priv id: uint,
     priv selector: &'port Select,
     priv next: *mut Handle<'static, ()>,
     priv prev: *mut Handle<'static, ()>,
@@ -150,11 +146,16 @@ impl Select {
 
     /// Waits for an event on this port set. The returned valus is *not* and
     /// index, but rather an id. This id can be queried against any active
-    /// `Handle` structures (each one has a public `id` field). The handle with
+    /// `Handle` structures (each one has an `id` method). The handle with
     /// the matching `id` will have some sort of event available on it. The
     /// event could either be that data is available or the corresponding
     /// channel has been closed.
     pub fn wait(&self) -> uint {
+        self.wait2(false)
+    }
+
+    /// Helper method for skipping the preflight checks during testing
+    fn wait2(&self, do_preflight_checks: bool) -> uint {
         // Note that this is currently an inefficient implementation. We in
         // theory have knowledge about all ports in the set ahead of time, so
         // this method shouldn't really have to iterate over all of them yet
@@ -179,7 +180,7 @@ impl Select {
             let mut amt = 0;
             for p in self.iter() {
                 amt += 1;
-                if (*p).packet.can_recv() {
+                if do_preflight_checks && (*p).packet.can_recv() {
                     return (*p).id;
                 }
             }
@@ -242,6 +243,10 @@ impl Select {
 }
 
 impl<'port, T: Send> Handle<'port, T> {
+    /// Retrieve the id of this handle.
+    #[inline]
+    pub fn id(&self) -> uint { self.id }
+
     /// Receive a value on the underlying port. Has the same semantics as
     /// `Port.recv`
     pub fn recv(&mut self) -> T { self.port.recv() }
@@ -355,7 +360,7 @@ mod test {
         )
         drop(c2);
         select! (
-            bar = p2.recv_opt() => { assert_eq!(bar, None); },
+            bar = p2.recv_opt() => { assert_eq!(bar, None); }
         )
     })
 
@@ -507,7 +512,7 @@ mod test {
         let (p2, c2) = Chan::<()>::new();
         let (p, c) = Chan::new();
         spawn(proc() {
-            let mut s = Select::new();
+            let s = Select::new();
             let mut h1 = s.handle(&p1);
             let mut h2 = s.handle(&p2);
             unsafe { h2.add(); }
@@ -521,4 +526,91 @@ mod test {
         c2.send(());
         p.recv();
     })
+
+    test!(fn preflight1() {
+        let (p, c) = Chan::new();
+        c.send(());
+        select!(
+            () = p.recv() => {}
+        )
+    })
+
+    test!(fn preflight2() {
+        let (p, c) = Chan::new();
+        c.send(());
+        c.send(());
+        select!(
+            () = p.recv() => {}
+        )
+    })
+
+    test!(fn preflight3() {
+        let (p, c) = Chan::new();
+        drop(c.clone());
+        c.send(());
+        select!(
+            () = p.recv() => {}
+        )
+    })
+
+    test!(fn preflight4() {
+        let (p, c) = Chan::new();
+        c.send(());
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
+
+    test!(fn preflight5() {
+        let (p, c) = Chan::new();
+        c.send(());
+        c.send(());
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
+
+    test!(fn preflight6() {
+        let (p, c) = Chan::new();
+        drop(c.clone());
+        c.send(());
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
+
+    test!(fn preflight7() {
+        let (p, c) = Chan::<()>::new();
+        drop(c);
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
+
+    test!(fn preflight8() {
+        let (p, c) = Chan::new();
+        c.send(());
+        drop(c);
+        p.recv();
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
+
+    test!(fn preflight9() {
+        let (p, c) = Chan::new();
+        drop(c.clone());
+        c.send(());
+        drop(c);
+        p.recv();
+        let s = Select::new();
+        let mut h = s.handle(&p);
+        unsafe { h.add(); }
+        assert_eq!(s.wait2(false), h.id);
+    })
 }