|  | //! Tests for channel selection using the `Select` struct. | 
|  |  | 
|  | extern crate crossbeam_channel; | 
|  | extern crate crossbeam_utils; | 
|  |  | 
|  | use std::any::Any; | 
|  | use std::cell::Cell; | 
|  | use std::thread; | 
|  | use std::time::{Duration, Instant}; | 
|  |  | 
|  | use crossbeam_channel::{after, bounded, tick, unbounded, Receiver, Select, TryRecvError}; | 
|  | use crossbeam_utils::thread::scope; | 
|  |  | 
|  | fn ms(ms: u64) -> Duration { | 
|  | Duration::from_millis(ms) | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn smoke1() { | 
|  | let (s1, r1) = unbounded::<usize>(); | 
|  | let (s2, r2) = unbounded::<usize>(); | 
|  |  | 
|  | s1.send(1).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | } | 
|  |  | 
|  | s2.send(2).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn smoke2() { | 
|  | let (_s1, r1) = unbounded::<i32>(); | 
|  | let (_s2, r2) = unbounded::<i32>(); | 
|  | let (_s3, r3) = unbounded::<i32>(); | 
|  | let (_s4, r4) = unbounded::<i32>(); | 
|  | let (s5, r5) = unbounded::<i32>(); | 
|  |  | 
|  | s5.send(5).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper3 = sel.recv(&r3); | 
|  | let oper4 = sel.recv(&r4); | 
|  | let oper5 = sel.recv(&r5); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => panic!(), | 
|  | i if i == oper3 => panic!(), | 
|  | i if i == oper4 => panic!(), | 
|  | i if i == oper5 => assert_eq!(oper.recv(&r5), Ok(5)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn disconnected() { | 
|  | let (s1, r1) = unbounded::<i32>(); | 
|  | let (s2, r2) = unbounded::<i32>(); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | drop(s1); | 
|  | thread::sleep(ms(500)); | 
|  | s2.send(5).unwrap(); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r1).is_err()), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | r2.recv().unwrap(); | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r1).is_err()), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(500)); | 
|  | drop(s2); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r2).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn default() { | 
|  | let (s1, r1) = unbounded::<i32>(); | 
|  | let (s2, r2) = unbounded::<i32>(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let _oper1 = sel.recv(&r1); | 
|  | let _oper2 = sel.recv(&r2); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(_) => panic!(), | 
|  | } | 
|  |  | 
|  | drop(s1); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r1).is_err()), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | s2.send(2).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r2); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert_eq!(oper.recv(&r2), Ok(2)), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let _oper1 = sel.recv(&r2); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(_) => panic!(), | 
|  | } | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(_) => panic!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn timeout() { | 
|  | let (_s1, r1) = unbounded::<i32>(); | 
|  | let (s2, r2) = unbounded::<i32>(); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(1500)); | 
|  | s2.send(2).unwrap(); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | scope(|scope| { | 
|  | let (s, r) = unbounded::<i32>(); | 
|  |  | 
|  | scope.spawn(move |_| { | 
|  | thread::sleep(ms(500)); | 
|  | drop(s); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | } | 
|  | Ok(_) => unreachable!(), | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn default_when_disconnected() { | 
|  | let (_, r) = unbounded::<i32>(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let (_, r) = unbounded::<i32>(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let (s, _) = bounded::<i32>(0); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.send(&s, 0).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let (s, _) = bounded::<i32>(0); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert!(oper.send(&s, 0).is_err()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn default_only() { | 
|  | let start = Instant::now(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper = sel.try_select(); | 
|  | assert!(oper.is_err()); | 
|  | let now = Instant::now(); | 
|  | assert!(now - start <= ms(50)); | 
|  |  | 
|  | let start = Instant::now(); | 
|  | let mut sel = Select::new(); | 
|  | let oper = sel.select_timeout(ms(500)); | 
|  | assert!(oper.is_err()); | 
|  | let now = Instant::now(); | 
|  | assert!(now - start >= ms(450)); | 
|  | assert!(now - start <= ms(550)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn unblocks() { | 
|  | let (s1, r1) = bounded::<i32>(0); | 
|  | let (s2, r2) = bounded::<i32>(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(500)); | 
|  | s2.send(2).unwrap(); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(500)); | 
|  | assert_eq!(r1.recv().unwrap(), 1); | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s1); | 
|  | let oper2 = sel.send(&s2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => oper.send(&s1, 1).unwrap(), | 
|  | i if i == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn both_ready() { | 
|  | let (s1, r1) = bounded(0); | 
|  | let (s2, r2) = bounded(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(500)); | 
|  | s1.send(1).unwrap(); | 
|  | assert_eq!(r2.recv().unwrap(), 2); | 
|  | }); | 
|  |  | 
|  | for _ in 0..2 { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.send(&s2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), | 
|  | i if i == oper2 => oper.send(&s2, 2).unwrap(), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn loop_try() { | 
|  | const RUNS: usize = 20; | 
|  |  | 
|  | for _ in 0..RUNS { | 
|  | let (s1, r1) = bounded::<i32>(0); | 
|  | let (s2, r2) = bounded::<i32>(0); | 
|  | let (s_end, r_end) = bounded::<()>(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| loop { | 
|  | let mut done = false; | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s1); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => { | 
|  | let _ = oper.send(&s1, 1); | 
|  | done = true; | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | if done { | 
|  | break; | 
|  | } | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r_end); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => { | 
|  | let _ = oper.recv(&r_end); | 
|  | done = true; | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | if done { | 
|  | break; | 
|  | } | 
|  | }); | 
|  |  | 
|  | scope.spawn(|_| loop { | 
|  | if let Ok(x) = r2.try_recv() { | 
|  | assert_eq!(x, 2); | 
|  | break; | 
|  | } | 
|  |  | 
|  | let mut done = false; | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r_end); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => { | 
|  | let _ = oper.recv(&r_end); | 
|  | done = true; | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | if done { | 
|  | break; | 
|  | } | 
|  | }); | 
|  |  | 
|  | scope.spawn(|_| { | 
|  | thread::sleep(ms(500)); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.send(&s2); | 
|  | let oper = sel.select_timeout(ms(1000)); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), | 
|  | i if i == oper2 => assert!(oper.send(&s2, 2).is_ok()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | drop(s_end); | 
|  | }); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn cloning1() { | 
|  | scope(|scope| { | 
|  | let (s1, r1) = unbounded::<i32>(); | 
|  | let (_s2, r2) = unbounded::<i32>(); | 
|  | let (s3, r3) = unbounded::<()>(); | 
|  |  | 
|  | scope.spawn(move |_| { | 
|  | r3.recv().unwrap(); | 
|  | drop(s1.clone()); | 
|  | assert!(r3.try_recv().is_err()); | 
|  | s1.send(1).unwrap(); | 
|  | r3.recv().unwrap(); | 
|  | }); | 
|  |  | 
|  | s3.send(()).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => drop(oper.recv(&r1)), | 
|  | i if i == oper2 => drop(oper.recv(&r2)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  |  | 
|  | s3.send(()).unwrap(); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn cloning2() { | 
|  | let (s1, r1) = unbounded::<()>(); | 
|  | let (s2, r2) = unbounded::<()>(); | 
|  | let (_s3, _r3) = unbounded::<()>(); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(move |_| { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => panic!(), | 
|  | i if i == oper2 => drop(oper.recv(&r2)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }); | 
|  |  | 
|  | thread::sleep(ms(500)); | 
|  | drop(s1.clone()); | 
|  | s2.send(()).unwrap(); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn preflight1() { | 
|  | let (s, r) = unbounded(); | 
|  | s.send(()).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => drop(oper.recv(&r)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn preflight2() { | 
|  | let (s, r) = unbounded(); | 
|  | drop(s.clone()); | 
|  | s.send(()).unwrap(); | 
|  | drop(s); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => assert_eq!(oper.recv(&r), Ok(())), | 
|  | _ => unreachable!(), | 
|  | } | 
|  |  | 
|  | assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn preflight3() { | 
|  | let (s, r) = unbounded(); | 
|  | drop(s.clone()); | 
|  | s.send(()).unwrap(); | 
|  | drop(s); | 
|  | r.recv().unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => assert!(oper.recv(&r).is_err()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn duplicate_operations() { | 
|  | let (s, r) = unbounded::<i32>(); | 
|  | let hit = vec![Cell::new(false); 4]; | 
|  |  | 
|  | while hit.iter().map(|h| h.get()).any(|hit| !hit) { | 
|  | let mut sel = Select::new(); | 
|  | let oper0 = sel.recv(&r); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper2 = sel.send(&s); | 
|  | let oper3 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper0 => { | 
|  | assert!(oper.recv(&r).is_ok()); | 
|  | hit[0].set(true); | 
|  | } | 
|  | i if i == oper1 => { | 
|  | assert!(oper.recv(&r).is_ok()); | 
|  | hit[1].set(true); | 
|  | } | 
|  | i if i == oper2 => { | 
|  | assert!(oper.send(&s, 0).is_ok()); | 
|  | hit[2].set(true); | 
|  | } | 
|  | i if i == oper3 => { | 
|  | assert!(oper.send(&s, 0).is_ok()); | 
|  | hit[3].set(true); | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn nesting() { | 
|  | let (s, r) = unbounded::<i32>(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | assert!(oper.send(&s, 0).is_ok()); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | assert_eq!(oper.recv(&r), Ok(0)); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | assert!(oper.send(&s, 1).is_ok()); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | assert_eq!(oper.recv(&r), Ok(1)); | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn stress_recv() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = unbounded(); | 
|  | let (s2, r2) = bounded(5); | 
|  | let (s3, r3) = bounded(100); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | s1.send(i).unwrap(); | 
|  | r3.recv().unwrap(); | 
|  |  | 
|  | s2.send(i).unwrap(); | 
|  | r3.recv().unwrap(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | for i in 0..COUNT { | 
|  | for _ in 0..2 { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), | 
|  | ix if ix == oper2 => assert_eq!(oper.recv(&r2), Ok(i)), | 
|  | _ => unreachable!(), | 
|  | } | 
|  |  | 
|  | s3.send(()).unwrap(); | 
|  | } | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn stress_send() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = bounded(0); | 
|  | let (s2, r2) = bounded(0); | 
|  | let (s3, r3) = bounded(100); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | assert_eq!(r1.recv().unwrap(), i); | 
|  | assert_eq!(r2.recv().unwrap(), i); | 
|  | r3.recv().unwrap(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | for i in 0..COUNT { | 
|  | for _ in 0..2 { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s1); | 
|  | let oper2 = sel.send(&s2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert!(oper.send(&s1, i).is_ok()), | 
|  | ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | s3.send(()).unwrap(); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn stress_mixed() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = bounded(0); | 
|  | let (s2, r2) = bounded(0); | 
|  | let (s3, r3) = bounded(100); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | s1.send(i).unwrap(); | 
|  | assert_eq!(r2.recv().unwrap(), i); | 
|  | r3.recv().unwrap(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | for i in 0..COUNT { | 
|  | for _ in 0..2 { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.send(&s2); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | s3.send(()).unwrap(); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn stress_timeout_two_threads() { | 
|  | const COUNT: usize = 20; | 
|  |  | 
|  | let (s, r) = bounded(2); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | if i % 2 == 0 { | 
|  | thread::sleep(ms(500)); | 
|  | } | 
|  |  | 
|  | let done = false; | 
|  | while !done { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.select_timeout(ms(100)); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => { | 
|  | assert!(oper.send(&s, i).is_ok()); | 
|  | break; | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | if i % 2 == 0 { | 
|  | thread::sleep(ms(500)); | 
|  | } | 
|  |  | 
|  | let mut done = false; | 
|  | while !done { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select_timeout(ms(100)); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => { | 
|  | assert_eq!(oper.recv(&r), Ok(i)); | 
|  | done = true; | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | } | 
|  | } | 
|  | }); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn send_recv_same_channel() { | 
|  | let (s, r) = bounded::<i32>(0); | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper2 = sel.recv(&r); | 
|  | let oper = sel.select_timeout(ms(100)); | 
|  | match oper { | 
|  | Err(_) => {} | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => panic!(), | 
|  | ix if ix == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | let (s, r) = unbounded::<i32>(); | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper2 = sel.recv(&r); | 
|  | let oper = sel.select_timeout(ms(100)); | 
|  | match oper { | 
|  | Err(_) => panic!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => assert!(oper.send(&s, 0).is_ok()), | 
|  | ix if ix == oper2 => panic!(), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn matching() { | 
|  | const THREADS: usize = 44; | 
|  |  | 
|  | let (s, r) = &bounded::<usize>(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | for i in 0..THREADS { | 
|  | scope.spawn(move |_| { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper2 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn matching_with_leftover() { | 
|  | const THREADS: usize = 55; | 
|  |  | 
|  | let (s, r) = &bounded::<usize>(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | for i in 0..THREADS { | 
|  | scope.spawn(move |_| { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper2 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }); | 
|  | } | 
|  | s.send(!0).unwrap(); | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn channel_through_channel() { | 
|  | const COUNT: usize = 1000; | 
|  |  | 
|  | type T = Box<dyn Any + Send>; | 
|  |  | 
|  | for cap in 0..3 { | 
|  | let (s, r) = bounded::<T>(cap); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(move |_| { | 
|  | let mut s = s; | 
|  |  | 
|  | for _ in 0..COUNT { | 
|  | let (new_s, new_r) = bounded(cap); | 
|  | let new_r: T = Box::new(Some(new_r)); | 
|  |  | 
|  | { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.send(&s); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert!(oper.send(&s, new_r).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | s = new_s; | 
|  | } | 
|  | }); | 
|  |  | 
|  | scope.spawn(move |_| { | 
|  | let mut r = r; | 
|  |  | 
|  | for _ in 0..COUNT { | 
|  | let new = { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => oper | 
|  | .recv(&r) | 
|  | .unwrap() | 
|  | .downcast_mut::<Option<Receiver<T>>>() | 
|  | .unwrap() | 
|  | .take() | 
|  | .unwrap(), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }; | 
|  | r = new; | 
|  | } | 
|  | }); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn linearizable_try() { | 
|  | const COUNT: usize = 100_000; | 
|  |  | 
|  | for step in 0..2 { | 
|  | let (start_s, start_r) = bounded::<()>(0); | 
|  | let (end_s, end_r) = bounded::<()>(0); | 
|  |  | 
|  | let ((s1, r1), (s2, r2)) = if step == 0 { | 
|  | (bounded::<i32>(1), bounded::<i32>(1)) | 
|  | } else { | 
|  | (unbounded::<i32>(), unbounded::<i32>()) | 
|  | }; | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for _ in 0..COUNT { | 
|  | start_s.send(()).unwrap(); | 
|  |  | 
|  | s1.send(1).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.try_select(); | 
|  | match oper { | 
|  | Err(_) => unreachable!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), | 
|  | ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | end_s.send(()).unwrap(); | 
|  | let _ = r2.try_recv(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | for _ in 0..COUNT { | 
|  | start_r.recv().unwrap(); | 
|  |  | 
|  | s2.send(1).unwrap(); | 
|  | let _ = r1.try_recv(); | 
|  |  | 
|  | end_r.recv().unwrap(); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn linearizable_timeout() { | 
|  | const COUNT: usize = 100_000; | 
|  |  | 
|  | for step in 0..2 { | 
|  | let (start_s, start_r) = bounded::<()>(0); | 
|  | let (end_s, end_r) = bounded::<()>(0); | 
|  |  | 
|  | let ((s1, r1), (s2, r2)) = if step == 0 { | 
|  | (bounded::<i32>(1), bounded::<i32>(1)) | 
|  | } else { | 
|  | (unbounded::<i32>(), unbounded::<i32>()) | 
|  | }; | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for _ in 0..COUNT { | 
|  | start_s.send(()).unwrap(); | 
|  |  | 
|  | s1.send(1).unwrap(); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper = sel.select_timeout(ms(0)); | 
|  | match oper { | 
|  | Err(_) => unreachable!(), | 
|  | Ok(oper) => match oper.index() { | 
|  | ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), | 
|  | ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), | 
|  | _ => unreachable!(), | 
|  | }, | 
|  | } | 
|  |  | 
|  | end_s.send(()).unwrap(); | 
|  | let _ = r2.try_recv(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | for _ in 0..COUNT { | 
|  | start_r.recv().unwrap(); | 
|  |  | 
|  | s2.send(1).unwrap(); | 
|  | let _ = r1.try_recv(); | 
|  |  | 
|  | end_r.recv().unwrap(); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn fairness1() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = bounded::<()>(COUNT); | 
|  | let (s2, r2) = unbounded::<()>(); | 
|  |  | 
|  | for _ in 0..COUNT { | 
|  | s1.send(()).unwrap(); | 
|  | s2.send(()).unwrap(); | 
|  | } | 
|  |  | 
|  | let hits = vec![Cell::new(0usize); 4]; | 
|  | for _ in 0..COUNT { | 
|  | let after = after(ms(0)); | 
|  | let tick = tick(ms(0)); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper3 = sel.recv(&after); | 
|  | let oper4 = sel.recv(&tick); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | oper.recv(&r1).unwrap(); | 
|  | hits[0].set(hits[0].get() + 1); | 
|  | } | 
|  | i if i == oper2 => { | 
|  | oper.recv(&r2).unwrap(); | 
|  | hits[1].set(hits[1].get() + 1); | 
|  | } | 
|  | i if i == oper3 => { | 
|  | oper.recv(&after).unwrap(); | 
|  | hits[2].set(hits[2].get() + 1); | 
|  | } | 
|  | i if i == oper4 => { | 
|  | oper.recv(&tick).unwrap(); | 
|  | hits[3].set(hits[3].get() + 1); | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn fairness2() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = unbounded::<()>(); | 
|  | let (s2, r2) = bounded::<()>(1); | 
|  | let (s3, r3) = bounded::<()>(0); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for _ in 0..COUNT { | 
|  | let mut sel = Select::new(); | 
|  | let mut oper1 = None; | 
|  | let mut oper2 = None; | 
|  | if s1.is_empty() { | 
|  | oper1 = Some(sel.send(&s1)); | 
|  | } | 
|  | if s2.is_empty() { | 
|  | oper2 = Some(sel.send(&s2)); | 
|  | } | 
|  | let oper3 = sel.send(&s3); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), | 
|  | i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), | 
|  | i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | let hits = vec![Cell::new(0usize); 3]; | 
|  | for _ in 0..COUNT { | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.recv(&r2); | 
|  | let oper3 = sel.recv(&r3); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | i if i == oper1 => { | 
|  | oper.recv(&r1).unwrap(); | 
|  | hits[0].set(hits[0].get() + 1); | 
|  | } | 
|  | i if i == oper2 => { | 
|  | oper.recv(&r2).unwrap(); | 
|  | hits[1].set(hits[1].get() + 1); | 
|  | } | 
|  | i if i == oper3 => { | 
|  | oper.recv(&r3).unwrap(); | 
|  | hits[2].set(hits[2].get() + 1); | 
|  | } | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn sync_and_clone() { | 
|  | const THREADS: usize = 20; | 
|  |  | 
|  | let (s, r) = &bounded::<usize>(0); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper2 = sel.send(&s); | 
|  | let sel = &sel; | 
|  |  | 
|  | scope(|scope| { | 
|  | for i in 0..THREADS { | 
|  | scope.spawn(move |_| { | 
|  | let mut sel = sel.clone(); | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn send_and_clone() { | 
|  | const THREADS: usize = 20; | 
|  |  | 
|  | let (s, r) = &bounded::<usize>(0); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r); | 
|  | let oper2 = sel.send(&s); | 
|  |  | 
|  | scope(|scope| { | 
|  | for i in 0..THREADS { | 
|  | let mut sel = sel.clone(); | 
|  | scope.spawn(move |_| { | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | }); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn reuse() { | 
|  | const COUNT: usize = 10_000; | 
|  |  | 
|  | let (s1, r1) = bounded(0); | 
|  | let (s2, r2) = bounded(0); | 
|  | let (s3, r3) = bounded(100); | 
|  |  | 
|  | scope(|scope| { | 
|  | scope.spawn(|_| { | 
|  | for i in 0..COUNT { | 
|  | s1.send(i).unwrap(); | 
|  | assert_eq!(r2.recv().unwrap(), i); | 
|  | r3.recv().unwrap(); | 
|  | } | 
|  | }); | 
|  |  | 
|  | let mut sel = Select::new(); | 
|  | let oper1 = sel.recv(&r1); | 
|  | let oper2 = sel.send(&s2); | 
|  |  | 
|  | for i in 0..COUNT { | 
|  | for _ in 0..2 { | 
|  | let oper = sel.select(); | 
|  | match oper.index() { | 
|  | ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), | 
|  | ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  | s3.send(()).unwrap(); | 
|  | } | 
|  | }) | 
|  | .unwrap(); | 
|  | } |