1 //! Tests for the `select!` macro.
2
3 #![forbid(unsafe_code)] // select! is safe.
4 #![allow(clippy::drop_copy, clippy::match_single_binding)]
5
6 use std::any::Any;
7 use std::cell::Cell;
8 use std::ops::Deref;
9 use std::thread;
10 use std::time::{Duration, Instant};
11
12 use crossbeam_channel::{after, bounded, never, select, tick, unbounded};
13 use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError};
14 use crossbeam_utils::thread::scope;
15
ms(ms: u64) -> Duration16 fn ms(ms: u64) -> Duration {
17 Duration::from_millis(ms)
18 }
19
20 #[test]
smoke1()21 fn smoke1() {
22 let (s1, r1) = unbounded::<usize>();
23 let (s2, r2) = unbounded::<usize>();
24
25 s1.send(1).unwrap();
26
27 select! {
28 recv(r1) -> v => assert_eq!(v, Ok(1)),
29 recv(r2) -> _ => panic!(),
30 }
31
32 s2.send(2).unwrap();
33
34 select! {
35 recv(r1) -> _ => panic!(),
36 recv(r2) -> v => assert_eq!(v, Ok(2)),
37 }
38 }
39
40 #[test]
smoke2()41 fn smoke2() {
42 let (_s1, r1) = unbounded::<i32>();
43 let (_s2, r2) = unbounded::<i32>();
44 let (_s3, r3) = unbounded::<i32>();
45 let (_s4, r4) = unbounded::<i32>();
46 let (s5, r5) = unbounded::<i32>();
47
48 s5.send(5).unwrap();
49
50 select! {
51 recv(r1) -> _ => panic!(),
52 recv(r2) -> _ => panic!(),
53 recv(r3) -> _ => panic!(),
54 recv(r4) -> _ => panic!(),
55 recv(r5) -> v => assert_eq!(v, Ok(5)),
56 }
57 }
58
59 #[test]
disconnected()60 fn disconnected() {
61 let (s1, r1) = unbounded::<i32>();
62 let (s2, r2) = unbounded::<i32>();
63
64 scope(|scope| {
65 scope.spawn(|_| {
66 drop(s1);
67 thread::sleep(ms(500));
68 s2.send(5).unwrap();
69 });
70
71 select! {
72 recv(r1) -> v => assert!(v.is_err()),
73 recv(r2) -> _ => panic!(),
74 default(ms(1000)) => panic!(),
75 }
76
77 r2.recv().unwrap();
78 })
79 .unwrap();
80
81 select! {
82 recv(r1) -> v => assert!(v.is_err()),
83 recv(r2) -> _ => panic!(),
84 default(ms(1000)) => panic!(),
85 }
86
87 scope(|scope| {
88 scope.spawn(|_| {
89 thread::sleep(ms(500));
90 drop(s2);
91 });
92
93 select! {
94 recv(r2) -> v => assert!(v.is_err()),
95 default(ms(1000)) => panic!(),
96 }
97 })
98 .unwrap();
99 }
100
101 #[test]
default()102 fn default() {
103 let (s1, r1) = unbounded::<i32>();
104 let (s2, r2) = unbounded::<i32>();
105
106 select! {
107 recv(r1) -> _ => panic!(),
108 recv(r2) -> _ => panic!(),
109 default => {}
110 }
111
112 drop(s1);
113
114 select! {
115 recv(r1) -> v => assert!(v.is_err()),
116 recv(r2) -> _ => panic!(),
117 default => panic!(),
118 }
119
120 s2.send(2).unwrap();
121
122 select! {
123 recv(r2) -> v => assert_eq!(v, Ok(2)),
124 default => panic!(),
125 }
126
127 select! {
128 recv(r2) -> _ => panic!(),
129 default => {},
130 }
131
132 select! {
133 default => {},
134 }
135 }
136
137 #[test]
timeout()138 fn timeout() {
139 let (_s1, r1) = unbounded::<i32>();
140 let (s2, r2) = unbounded::<i32>();
141
142 scope(|scope| {
143 scope.spawn(|_| {
144 thread::sleep(ms(1500));
145 s2.send(2).unwrap();
146 });
147
148 select! {
149 recv(r1) -> _ => panic!(),
150 recv(r2) -> _ => panic!(),
151 default(ms(1000)) => {},
152 }
153
154 select! {
155 recv(r1) -> _ => panic!(),
156 recv(r2) -> v => assert_eq!(v, Ok(2)),
157 default(ms(1000)) => panic!(),
158 }
159 })
160 .unwrap();
161
162 scope(|scope| {
163 let (s, r) = unbounded::<i32>();
164
165 scope.spawn(move |_| {
166 thread::sleep(ms(500));
167 drop(s);
168 });
169
170 select! {
171 default(ms(1000)) => {
172 select! {
173 recv(r) -> v => assert!(v.is_err()),
174 default => panic!(),
175 }
176 }
177 }
178 })
179 .unwrap();
180 }
181
182 #[test]
default_when_disconnected()183 fn default_when_disconnected() {
184 let (_, r) = unbounded::<i32>();
185
186 select! {
187 recv(r) -> res => assert!(res.is_err()),
188 default => panic!(),
189 }
190
191 let (_, r) = unbounded::<i32>();
192
193 select! {
194 recv(r) -> res => assert!(res.is_err()),
195 default(ms(1000)) => panic!(),
196 }
197
198 let (s, _) = bounded::<i32>(0);
199
200 select! {
201 send(s, 0) -> res => assert!(res.is_err()),
202 default => panic!(),
203 }
204
205 let (s, _) = bounded::<i32>(0);
206
207 select! {
208 send(s, 0) -> res => assert!(res.is_err()),
209 default(ms(1000)) => panic!(),
210 }
211 }
212
213 #[test]
default_only()214 fn default_only() {
215 let start = Instant::now();
216 select! {
217 default => {}
218 }
219 let now = Instant::now();
220 assert!(now - start <= ms(50));
221
222 let start = Instant::now();
223 select! {
224 default(ms(500)) => {}
225 }
226 let now = Instant::now();
227 assert!(now - start >= ms(450));
228 assert!(now - start <= ms(550));
229 }
230
231 #[test]
unblocks()232 fn unblocks() {
233 let (s1, r1) = bounded::<i32>(0);
234 let (s2, r2) = bounded::<i32>(0);
235
236 scope(|scope| {
237 scope.spawn(|_| {
238 thread::sleep(ms(500));
239 s2.send(2).unwrap();
240 });
241
242 select! {
243 recv(r1) -> _ => panic!(),
244 recv(r2) -> v => assert_eq!(v, Ok(2)),
245 default(ms(1000)) => panic!(),
246 }
247 })
248 .unwrap();
249
250 scope(|scope| {
251 scope.spawn(|_| {
252 thread::sleep(ms(500));
253 assert_eq!(r1.recv().unwrap(), 1);
254 });
255
256 select! {
257 send(s1, 1) -> _ => {},
258 send(s2, 2) -> _ => panic!(),
259 default(ms(1000)) => panic!(),
260 }
261 })
262 .unwrap();
263 }
264
265 #[test]
both_ready()266 fn both_ready() {
267 let (s1, r1) = bounded(0);
268 let (s2, r2) = bounded(0);
269
270 scope(|scope| {
271 scope.spawn(|_| {
272 thread::sleep(ms(500));
273 s1.send(1).unwrap();
274 assert_eq!(r2.recv().unwrap(), 2);
275 });
276
277 for _ in 0..2 {
278 select! {
279 recv(r1) -> v => assert_eq!(v, Ok(1)),
280 send(s2, 2) -> _ => {},
281 }
282 }
283 })
284 .unwrap();
285 }
286
287 #[test]
loop_try()288 fn loop_try() {
289 const RUNS: usize = 20;
290
291 for _ in 0..RUNS {
292 let (s1, r1) = bounded::<i32>(0);
293 let (s2, r2) = bounded::<i32>(0);
294 let (s_end, r_end) = bounded::<()>(0);
295
296 scope(|scope| {
297 scope.spawn(|_| loop {
298 select! {
299 send(s1, 1) -> _ => break,
300 default => {}
301 }
302
303 select! {
304 recv(r_end) -> _ => break,
305 default => {}
306 }
307 });
308
309 scope.spawn(|_| loop {
310 if let Ok(x) = r2.try_recv() {
311 assert_eq!(x, 2);
312 break;
313 }
314
315 select! {
316 recv(r_end) -> _ => break,
317 default => {}
318 }
319 });
320
321 scope.spawn(|_| {
322 thread::sleep(ms(500));
323
324 select! {
325 recv(r1) -> v => assert_eq!(v, Ok(1)),
326 send(s2, 2) -> _ => {},
327 default(ms(500)) => panic!(),
328 }
329
330 drop(s_end);
331 });
332 })
333 .unwrap();
334 }
335 }
336
337 #[test]
cloning1()338 fn cloning1() {
339 scope(|scope| {
340 let (s1, r1) = unbounded::<i32>();
341 let (_s2, r2) = unbounded::<i32>();
342 let (s3, r3) = unbounded::<()>();
343
344 scope.spawn(move |_| {
345 r3.recv().unwrap();
346 drop(s1.clone());
347 assert_eq!(r3.try_recv(), Err(TryRecvError::Empty));
348 s1.send(1).unwrap();
349 r3.recv().unwrap();
350 });
351
352 s3.send(()).unwrap();
353
354 select! {
355 recv(r1) -> _ => {},
356 recv(r2) -> _ => {},
357 }
358
359 s3.send(()).unwrap();
360 })
361 .unwrap();
362 }
363
364 #[test]
cloning2()365 fn cloning2() {
366 let (s1, r1) = unbounded::<()>();
367 let (s2, r2) = unbounded::<()>();
368 let (_s3, _r3) = unbounded::<()>();
369
370 scope(|scope| {
371 scope.spawn(move |_| {
372 select! {
373 recv(r1) -> _ => panic!(),
374 recv(r2) -> _ => {},
375 }
376 });
377
378 thread::sleep(ms(500));
379 drop(s1.clone());
380 s2.send(()).unwrap();
381 })
382 .unwrap();
383 }
384
385 #[test]
preflight1()386 fn preflight1() {
387 let (s, r) = unbounded();
388 s.send(()).unwrap();
389
390 select! {
391 recv(r) -> _ => {}
392 }
393 }
394
395 #[test]
preflight2()396 fn preflight2() {
397 let (s, r) = unbounded();
398 drop(s.clone());
399 s.send(()).unwrap();
400 drop(s);
401
402 select! {
403 recv(r) -> v => assert!(v.is_ok()),
404 }
405 assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected));
406 }
407
408 #[test]
preflight3()409 fn preflight3() {
410 let (s, r) = unbounded();
411 drop(s.clone());
412 s.send(()).unwrap();
413 drop(s);
414 r.recv().unwrap();
415
416 select! {
417 recv(r) -> v => assert!(v.is_err())
418 }
419 }
420
421 #[test]
duplicate_operations()422 fn duplicate_operations() {
423 let (s, r) = unbounded::<i32>();
424 let mut hit = [false; 4];
425
426 while hit.iter().any(|hit| !hit) {
427 select! {
428 recv(r) -> _ => hit[0] = true,
429 recv(r) -> _ => hit[1] = true,
430 send(s, 0) -> _ => hit[2] = true,
431 send(s, 0) -> _ => hit[3] = true,
432 }
433 }
434 }
435
436 #[test]
nesting()437 fn nesting() {
438 let (s, r) = unbounded::<i32>();
439
440 select! {
441 send(s, 0) -> _ => {
442 select! {
443 recv(r) -> v => {
444 assert_eq!(v, Ok(0));
445 select! {
446 send(s, 1) -> _ => {
447 select! {
448 recv(r) -> v => {
449 assert_eq!(v, Ok(1));
450 }
451 }
452 }
453 }
454 }
455 }
456 }
457 }
458 }
459
460 #[test]
461 #[should_panic(expected = "send panicked")]
panic_sender()462 fn panic_sender() {
463 fn get() -> Sender<i32> {
464 panic!("send panicked")
465 }
466
467 #[allow(unreachable_code)]
468 {
469 select! {
470 send(get(), panic!()) -> _ => {}
471 }
472 }
473 }
474
475 #[test]
476 #[should_panic(expected = "recv panicked")]
panic_receiver()477 fn panic_receiver() {
478 fn get() -> Receiver<i32> {
479 panic!("recv panicked")
480 }
481
482 select! {
483 recv(get()) -> _ => {}
484 }
485 }
486
487 #[test]
stress_recv()488 fn stress_recv() {
489 #[cfg(miri)]
490 const COUNT: usize = 50;
491 #[cfg(not(miri))]
492 const COUNT: usize = 10_000;
493
494 let (s1, r1) = unbounded();
495 let (s2, r2) = bounded(5);
496 let (s3, r3) = bounded(100);
497
498 scope(|scope| {
499 scope.spawn(|_| {
500 for i in 0..COUNT {
501 s1.send(i).unwrap();
502 r3.recv().unwrap();
503
504 s2.send(i).unwrap();
505 r3.recv().unwrap();
506 }
507 });
508
509 for i in 0..COUNT {
510 for _ in 0..2 {
511 select! {
512 recv(r1) -> v => assert_eq!(v, Ok(i)),
513 recv(r2) -> v => assert_eq!(v, Ok(i)),
514 }
515
516 s3.send(()).unwrap();
517 }
518 }
519 })
520 .unwrap();
521 }
522
523 #[test]
stress_send()524 fn stress_send() {
525 #[cfg(miri)]
526 const COUNT: usize = 100;
527 #[cfg(not(miri))]
528 const COUNT: usize = 10_000;
529
530 let (s1, r1) = bounded(0);
531 let (s2, r2) = bounded(0);
532 let (s3, r3) = bounded(100);
533
534 scope(|scope| {
535 scope.spawn(|_| {
536 for i in 0..COUNT {
537 assert_eq!(r1.recv().unwrap(), i);
538 assert_eq!(r2.recv().unwrap(), i);
539 r3.recv().unwrap();
540 }
541 });
542
543 for i in 0..COUNT {
544 for _ in 0..2 {
545 select! {
546 send(s1, i) -> _ => {},
547 send(s2, i) -> _ => {},
548 }
549 }
550 s3.send(()).unwrap();
551 }
552 })
553 .unwrap();
554 }
555
556 #[test]
stress_mixed()557 fn stress_mixed() {
558 #[cfg(miri)]
559 const COUNT: usize = 100;
560 #[cfg(not(miri))]
561 const COUNT: usize = 10_000;
562
563 let (s1, r1) = bounded(0);
564 let (s2, r2) = bounded(0);
565 let (s3, r3) = bounded(100);
566
567 scope(|scope| {
568 scope.spawn(|_| {
569 for i in 0..COUNT {
570 s1.send(i).unwrap();
571 assert_eq!(r2.recv().unwrap(), i);
572 r3.recv().unwrap();
573 }
574 });
575
576 for i in 0..COUNT {
577 for _ in 0..2 {
578 select! {
579 recv(r1) -> v => assert_eq!(v, Ok(i)),
580 send(s2, i) -> _ => {},
581 }
582 }
583 s3.send(()).unwrap();
584 }
585 })
586 .unwrap();
587 }
588
589 #[test]
stress_timeout_two_threads()590 fn stress_timeout_two_threads() {
591 const COUNT: usize = 20;
592
593 let (s, r) = bounded(2);
594
595 scope(|scope| {
596 scope.spawn(|_| {
597 for i in 0..COUNT {
598 if i % 2 == 0 {
599 thread::sleep(ms(500));
600 }
601
602 loop {
603 select! {
604 send(s, i) -> _ => break,
605 default(ms(100)) => {}
606 }
607 }
608 }
609 });
610
611 scope.spawn(|_| {
612 for i in 0..COUNT {
613 if i % 2 == 0 {
614 thread::sleep(ms(500));
615 }
616
617 loop {
618 select! {
619 recv(r) -> v => {
620 assert_eq!(v, Ok(i));
621 break;
622 }
623 default(ms(100)) => {}
624 }
625 }
626 }
627 });
628 })
629 .unwrap();
630 }
631
632 #[test]
send_recv_same_channel()633 fn send_recv_same_channel() {
634 let (s, r) = bounded::<i32>(0);
635 select! {
636 send(s, 0) -> _ => panic!(),
637 recv(r) -> _ => panic!(),
638 default(ms(500)) => {}
639 }
640
641 let (s, r) = unbounded::<i32>();
642 select! {
643 send(s, 0) -> _ => {},
644 recv(r) -> _ => panic!(),
645 default(ms(500)) => panic!(),
646 }
647 }
648
649 #[test]
matching()650 fn matching() {
651 const THREADS: usize = 44;
652
653 let (s, r) = &bounded::<usize>(0);
654
655 scope(|scope| {
656 for i in 0..THREADS {
657 scope.spawn(move |_| {
658 select! {
659 recv(r) -> v => assert_ne!(v.unwrap(), i),
660 send(s, i) -> _ => {},
661 }
662 });
663 }
664 })
665 .unwrap();
666
667 assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
668 }
669
670 #[test]
matching_with_leftover()671 fn matching_with_leftover() {
672 const THREADS: usize = 55;
673
674 let (s, r) = &bounded::<usize>(0);
675
676 scope(|scope| {
677 for i in 0..THREADS {
678 scope.spawn(move |_| {
679 select! {
680 recv(r) -> v => assert_ne!(v.unwrap(), i),
681 send(s, i) -> _ => {},
682 }
683 });
684 }
685 s.send(!0).unwrap();
686 })
687 .unwrap();
688
689 assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
690 }
691
692 #[test]
channel_through_channel()693 fn channel_through_channel() {
694 #[cfg(miri)]
695 const COUNT: usize = 100;
696 #[cfg(not(miri))]
697 const COUNT: usize = 1000;
698
699 type T = Box<dyn Any + Send>;
700
701 for cap in 0..3 {
702 let (s, r) = bounded::<T>(cap);
703
704 scope(|scope| {
705 scope.spawn(move |_| {
706 let mut s = s;
707
708 for _ in 0..COUNT {
709 let (new_s, new_r) = bounded(cap);
710 let new_r: T = Box::new(Some(new_r));
711
712 select! {
713 send(s, new_r) -> _ => {}
714 }
715
716 s = new_s;
717 }
718 });
719
720 scope.spawn(move |_| {
721 let mut r = r;
722
723 for _ in 0..COUNT {
724 r = select! {
725 recv(r) -> msg => {
726 msg.unwrap()
727 .downcast_mut::<Option<Receiver<T>>>()
728 .unwrap()
729 .take()
730 .unwrap()
731 }
732 }
733 }
734 });
735 })
736 .unwrap();
737 }
738 }
739
740 #[test]
linearizable_default()741 fn linearizable_default() {
742 #[cfg(miri)]
743 const COUNT: usize = 100;
744 #[cfg(not(miri))]
745 const COUNT: usize = 100_000;
746
747 for step in 0..2 {
748 let (start_s, start_r) = bounded::<()>(0);
749 let (end_s, end_r) = bounded::<()>(0);
750
751 let ((s1, r1), (s2, r2)) = if step == 0 {
752 (bounded::<i32>(1), bounded::<i32>(1))
753 } else {
754 (unbounded::<i32>(), unbounded::<i32>())
755 };
756
757 scope(|scope| {
758 scope.spawn(|_| {
759 for _ in 0..COUNT {
760 start_s.send(()).unwrap();
761
762 s1.send(1).unwrap();
763 select! {
764 recv(r1) -> _ => {}
765 recv(r2) -> _ => {}
766 default => unreachable!()
767 }
768
769 end_s.send(()).unwrap();
770 let _ = r2.try_recv();
771 }
772 });
773
774 for _ in 0..COUNT {
775 start_r.recv().unwrap();
776
777 s2.send(1).unwrap();
778 let _ = r1.try_recv();
779
780 end_r.recv().unwrap();
781 }
782 })
783 .unwrap();
784 }
785 }
786
787 #[test]
linearizable_timeout()788 fn linearizable_timeout() {
789 #[cfg(miri)]
790 const COUNT: usize = 100;
791 #[cfg(not(miri))]
792 const COUNT: usize = 100_000;
793
794 for step in 0..2 {
795 let (start_s, start_r) = bounded::<()>(0);
796 let (end_s, end_r) = bounded::<()>(0);
797
798 let ((s1, r1), (s2, r2)) = if step == 0 {
799 (bounded::<i32>(1), bounded::<i32>(1))
800 } else {
801 (unbounded::<i32>(), unbounded::<i32>())
802 };
803
804 scope(|scope| {
805 scope.spawn(|_| {
806 for _ in 0..COUNT {
807 start_s.send(()).unwrap();
808
809 s1.send(1).unwrap();
810 select! {
811 recv(r1) -> _ => {}
812 recv(r2) -> _ => {}
813 default(ms(0)) => unreachable!()
814 }
815
816 end_s.send(()).unwrap();
817 let _ = r2.try_recv();
818 }
819 });
820
821 for _ in 0..COUNT {
822 start_r.recv().unwrap();
823
824 s2.send(1).unwrap();
825 let _ = r1.try_recv();
826
827 end_r.recv().unwrap();
828 }
829 })
830 .unwrap();
831 }
832 }
833
834 #[test]
fairness1()835 fn fairness1() {
836 #[cfg(miri)]
837 const COUNT: usize = 100;
838 #[cfg(not(miri))]
839 const COUNT: usize = 10_000;
840
841 let (s1, r1) = bounded::<()>(COUNT);
842 let (s2, r2) = unbounded::<()>();
843
844 for _ in 0..COUNT {
845 s1.send(()).unwrap();
846 s2.send(()).unwrap();
847 }
848
849 let mut hits = [0usize; 4];
850 for _ in 0..COUNT {
851 select! {
852 recv(r1) -> _ => hits[0] += 1,
853 recv(r2) -> _ => hits[1] += 1,
854 recv(after(ms(0))) -> _ => hits[2] += 1,
855 recv(tick(ms(0))) -> _ => hits[3] += 1,
856 }
857 }
858 assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
859 }
860
861 #[test]
fairness2()862 fn fairness2() {
863 #[cfg(miri)]
864 const COUNT: usize = 100;
865 #[cfg(not(miri))]
866 const COUNT: usize = 10_000;
867
868 let (s1, r1) = unbounded::<()>();
869 let (s2, r2) = bounded::<()>(1);
870 let (s3, r3) = bounded::<()>(0);
871
872 scope(|scope| {
873 scope.spawn(|_| {
874 let (hole, _r) = bounded(0);
875
876 for _ in 0..COUNT {
877 let s1 = if s1.is_empty() { &s1 } else { &hole };
878 let s2 = if s2.is_empty() { &s2 } else { &hole };
879
880 select! {
881 send(s1, ()) -> res => assert!(res.is_ok()),
882 send(s2, ()) -> res => assert!(res.is_ok()),
883 send(s3, ()) -> res => assert!(res.is_ok()),
884 }
885 }
886 });
887
888 let hits = vec![Cell::new(0usize); 3];
889 for _ in 0..COUNT {
890 select! {
891 recv(r1) -> _ => hits[0].set(hits[0].get() + 1),
892 recv(r2) -> _ => hits[1].set(hits[1].get() + 1),
893 recv(r3) -> _ => hits[2].set(hits[2].get() + 1),
894 }
895 }
896 assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50));
897 })
898 .unwrap();
899 }
900
901 #[test]
fairness_recv()902 fn fairness_recv() {
903 #[cfg(miri)]
904 const COUNT: usize = 100;
905 #[cfg(not(miri))]
906 const COUNT: usize = 10_000;
907
908 let (s1, r1) = bounded::<()>(COUNT);
909 let (s2, r2) = unbounded::<()>();
910
911 for _ in 0..COUNT {
912 s1.send(()).unwrap();
913 s2.send(()).unwrap();
914 }
915
916 let mut hits = [0usize; 2];
917 while hits[0] + hits[1] < COUNT {
918 select! {
919 recv(r1) -> _ => hits[0] += 1,
920 recv(r2) -> _ => hits[1] += 1,
921 }
922 }
923 assert!(hits.iter().all(|x| *x >= COUNT / 4));
924 }
925
926 #[test]
fairness_send()927 fn fairness_send() {
928 #[cfg(miri)]
929 const COUNT: usize = 100;
930 #[cfg(not(miri))]
931 const COUNT: usize = 10_000;
932
933 let (s1, _r1) = bounded::<()>(COUNT);
934 let (s2, _r2) = unbounded::<()>();
935
936 let mut hits = [0usize; 2];
937 for _ in 0..COUNT {
938 select! {
939 send(s1, ()) -> _ => hits[0] += 1,
940 send(s2, ()) -> _ => hits[1] += 1,
941 }
942 }
943 assert!(hits.iter().all(|x| *x >= COUNT / 4));
944 }
945
946 #[allow(clippy::or_fun_call)] // This is intentional.
947 #[test]
references()948 fn references() {
949 let (s, r) = unbounded::<i32>();
950 select! {
951 send(s, 0) -> _ => {}
952 recv(r) -> _ => {}
953 }
954 select! {
955 send(&&&&s, 0) -> _ => {}
956 recv(&&&&r) -> _ => {}
957 }
958 select! {
959 recv(Some(&r).unwrap_or(&never())) -> _ => {},
960 default => {}
961 }
962 select! {
963 recv(Some(r).unwrap_or(never())) -> _ => {},
964 default => {}
965 }
966 }
967
968 #[test]
case_blocks()969 fn case_blocks() {
970 let (s, r) = unbounded::<i32>();
971
972 select! {
973 recv(r) -> _ => 3.0,
974 recv(r) -> _ => loop {
975 unreachable!()
976 },
977 recv(r) -> _ => match 7 + 3 {
978 _ => unreachable!()
979 },
980 default => 7.
981 };
982
983 select! {
984 recv(r) -> msg => if msg.is_ok() {
985 unreachable!()
986 },
987 default => ()
988 }
989
990 drop(s);
991 }
992
993 #[allow(clippy::redundant_closure_call)] // This is intentional.
994 #[test]
move_handles()995 fn move_handles() {
996 let (s, r) = unbounded::<i32>();
997 select! {
998 recv((move || r)()) -> _ => {}
999 send((move || s)(), 0) -> _ => {}
1000 }
1001 }
1002
1003 #[test]
infer_types()1004 fn infer_types() {
1005 let (s, r) = unbounded();
1006 select! {
1007 recv(r) -> _ => {}
1008 default => {}
1009 }
1010 s.send(()).unwrap();
1011
1012 let (s, r) = unbounded();
1013 select! {
1014 send(s, ()) -> _ => {}
1015 }
1016 r.recv().unwrap();
1017 }
1018
1019 #[test]
default_syntax()1020 fn default_syntax() {
1021 let (s, r) = bounded::<i32>(0);
1022
1023 select! {
1024 recv(r) -> _ => panic!(),
1025 default => {}
1026 }
1027 select! {
1028 send(s, 0) -> _ => panic!(),
1029 default() => {}
1030 }
1031 select! {
1032 default => {}
1033 }
1034 select! {
1035 default() => {}
1036 }
1037 }
1038
1039 #[test]
same_variable_name()1040 fn same_variable_name() {
1041 let (_, r) = unbounded::<i32>();
1042 select! {
1043 recv(r) -> r => assert!(r.is_err()),
1044 }
1045 }
1046
1047 #[test]
handles_on_heap()1048 fn handles_on_heap() {
1049 let (s, r) = unbounded::<i32>();
1050 let (s, r) = (Box::new(s), Box::new(r));
1051
1052 select! {
1053 send(*s, 0) -> _ => {}
1054 recv(*r) -> _ => {}
1055 default => {}
1056 }
1057
1058 drop(s);
1059 drop(r);
1060 }
1061
1062 #[test]
once_blocks()1063 fn once_blocks() {
1064 let (s, r) = unbounded::<i32>();
1065
1066 let once = Box::new(());
1067 select! {
1068 send(s, 0) -> _ => drop(once),
1069 }
1070
1071 let once = Box::new(());
1072 select! {
1073 recv(r) -> _ => drop(once),
1074 }
1075
1076 let once1 = Box::new(());
1077 let once2 = Box::new(());
1078 select! {
1079 send(s, 0) -> _ => drop(once1),
1080 default => drop(once2),
1081 }
1082
1083 let once1 = Box::new(());
1084 let once2 = Box::new(());
1085 select! {
1086 recv(r) -> _ => drop(once1),
1087 default => drop(once2),
1088 }
1089
1090 let once1 = Box::new(());
1091 let once2 = Box::new(());
1092 select! {
1093 recv(r) -> _ => drop(once1),
1094 send(s, 0) -> _ => drop(once2),
1095 }
1096 }
1097
1098 #[test]
once_receiver()1099 fn once_receiver() {
1100 let (_, r) = unbounded::<i32>();
1101
1102 let once = Box::new(());
1103 let get = move || {
1104 drop(once);
1105 r
1106 };
1107
1108 select! {
1109 recv(get()) -> _ => {}
1110 }
1111 }
1112
1113 #[test]
once_sender()1114 fn once_sender() {
1115 let (s, _) = unbounded::<i32>();
1116
1117 let once = Box::new(());
1118 let get = move || {
1119 drop(once);
1120 s
1121 };
1122
1123 select! {
1124 send(get(), 5) -> _ => {}
1125 }
1126 }
1127
1128 #[test]
parse_nesting()1129 fn parse_nesting() {
1130 let (_, r) = unbounded::<i32>();
1131
1132 select! {
1133 recv(r) -> _ => {}
1134 recv(r) -> _ => {
1135 select! {
1136 recv(r) -> _ => {}
1137 recv(r) -> _ => {
1138 select! {
1139 recv(r) -> _ => {}
1140 recv(r) -> _ => {
1141 select! {
1142 default => {}
1143 }
1144 }
1145 }
1146 }
1147 }
1148 }
1149 }
1150 }
1151
1152 #[test]
evaluate()1153 fn evaluate() {
1154 let (s, r) = unbounded::<i32>();
1155
1156 let v = select! {
1157 recv(r) -> _ => "foo".into(),
1158 send(s, 0) -> _ => "bar".to_owned(),
1159 default => "baz".to_string(),
1160 };
1161 assert_eq!(v, "bar");
1162
1163 let v = select! {
1164 recv(r) -> _ => "foo".into(),
1165 default => "baz".to_string(),
1166 };
1167 assert_eq!(v, "foo");
1168
1169 let v = select! {
1170 recv(r) -> _ => "foo".into(),
1171 default => "baz".to_string(),
1172 };
1173 assert_eq!(v, "baz");
1174 }
1175
1176 #[test]
deref()1177 fn deref() {
1178 use crossbeam_channel as cc;
1179
1180 struct Sender<T>(cc::Sender<T>);
1181 struct Receiver<T>(cc::Receiver<T>);
1182
1183 impl<T> Deref for Receiver<T> {
1184 type Target = cc::Receiver<T>;
1185
1186 fn deref(&self) -> &Self::Target {
1187 &self.0
1188 }
1189 }
1190
1191 impl<T> Deref for Sender<T> {
1192 type Target = cc::Sender<T>;
1193
1194 fn deref(&self) -> &Self::Target {
1195 &self.0
1196 }
1197 }
1198
1199 let (s, r) = bounded::<i32>(0);
1200 let (s, r) = (Sender(s), Receiver(r));
1201
1202 select! {
1203 send(s, 0) -> _ => panic!(),
1204 recv(r) -> _ => panic!(),
1205 default => {}
1206 }
1207 }
1208
1209 #[test]
result_types()1210 fn result_types() {
1211 let (s, _) = bounded::<i32>(0);
1212 let (_, r) = bounded::<i32>(0);
1213
1214 select! {
1215 recv(r) -> res => drop::<Result<i32, RecvError>>(res),
1216 }
1217 select! {
1218 recv(r) -> res => drop::<Result<i32, RecvError>>(res),
1219 default => {}
1220 }
1221 select! {
1222 recv(r) -> res => drop::<Result<i32, RecvError>>(res),
1223 default(ms(0)) => {}
1224 }
1225
1226 select! {
1227 send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res),
1228 }
1229 select! {
1230 send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res),
1231 default => {}
1232 }
1233 select! {
1234 send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res),
1235 default(ms(0)) => {}
1236 }
1237
1238 select! {
1239 send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res),
1240 recv(r) -> res => drop::<Result<i32, RecvError>>(res),
1241 }
1242 }
1243
1244 #[test]
try_recv()1245 fn try_recv() {
1246 let (s, r) = bounded(0);
1247
1248 scope(|scope| {
1249 scope.spawn(move |_| {
1250 select! {
1251 recv(r) -> _ => panic!(),
1252 default => {}
1253 }
1254 thread::sleep(ms(1500));
1255 select! {
1256 recv(r) -> v => assert_eq!(v, Ok(7)),
1257 default => panic!(),
1258 }
1259 thread::sleep(ms(500));
1260 select! {
1261 recv(r) -> v => assert_eq!(v, Err(RecvError)),
1262 default => panic!(),
1263 }
1264 });
1265 scope.spawn(move |_| {
1266 thread::sleep(ms(1000));
1267 select! {
1268 send(s, 7) -> res => res.unwrap(),
1269 }
1270 });
1271 })
1272 .unwrap();
1273 }
1274
1275 #[test]
recv()1276 fn recv() {
1277 let (s, r) = bounded(0);
1278
1279 scope(|scope| {
1280 scope.spawn(move |_| {
1281 select! {
1282 recv(r) -> v => assert_eq!(v, Ok(7)),
1283 }
1284 thread::sleep(ms(1000));
1285 select! {
1286 recv(r) -> v => assert_eq!(v, Ok(8)),
1287 }
1288 thread::sleep(ms(1000));
1289 select! {
1290 recv(r) -> v => assert_eq!(v, Ok(9)),
1291 }
1292 select! {
1293 recv(r) -> v => assert_eq!(v, Err(RecvError)),
1294 }
1295 });
1296 scope.spawn(move |_| {
1297 thread::sleep(ms(1500));
1298 select! {
1299 send(s, 7) -> res => res.unwrap(),
1300 }
1301 select! {
1302 send(s, 8) -> res => res.unwrap(),
1303 }
1304 select! {
1305 send(s, 9) -> res => res.unwrap(),
1306 }
1307 });
1308 })
1309 .unwrap();
1310 }
1311
1312 #[test]
recv_timeout()1313 fn recv_timeout() {
1314 let (s, r) = bounded::<i32>(0);
1315
1316 scope(|scope| {
1317 scope.spawn(move |_| {
1318 select! {
1319 recv(r) -> _ => panic!(),
1320 default(ms(1000)) => {}
1321 }
1322 select! {
1323 recv(r) -> v => assert_eq!(v, Ok(7)),
1324 default(ms(1000)) => panic!(),
1325 }
1326 select! {
1327 recv(r) -> v => assert_eq!(v, Err(RecvError)),
1328 default(ms(1000)) => panic!(),
1329 }
1330 });
1331 scope.spawn(move |_| {
1332 thread::sleep(ms(1500));
1333 select! {
1334 send(s, 7) -> res => res.unwrap(),
1335 }
1336 });
1337 })
1338 .unwrap();
1339 }
1340
1341 #[test]
try_send()1342 fn try_send() {
1343 let (s, r) = bounded(0);
1344
1345 scope(|scope| {
1346 scope.spawn(move |_| {
1347 select! {
1348 send(s, 7) -> _ => panic!(),
1349 default => {}
1350 }
1351 thread::sleep(ms(1500));
1352 select! {
1353 send(s, 8) -> res => res.unwrap(),
1354 default => panic!(),
1355 }
1356 thread::sleep(ms(500));
1357 select! {
1358 send(s, 8) -> res => assert_eq!(res, Err(SendError(8))),
1359 default => panic!(),
1360 }
1361 });
1362 scope.spawn(move |_| {
1363 thread::sleep(ms(1000));
1364 select! {
1365 recv(r) -> v => assert_eq!(v, Ok(8)),
1366 }
1367 });
1368 })
1369 .unwrap();
1370 }
1371
1372 #[test]
send()1373 fn send() {
1374 let (s, r) = bounded(0);
1375
1376 scope(|scope| {
1377 scope.spawn(move |_| {
1378 select! {
1379 send(s, 7) -> res => res.unwrap(),
1380 }
1381 thread::sleep(ms(1000));
1382 select! {
1383 send(s, 8) -> res => res.unwrap(),
1384 }
1385 thread::sleep(ms(1000));
1386 select! {
1387 send(s, 9) -> res => res.unwrap(),
1388 }
1389 });
1390 scope.spawn(move |_| {
1391 thread::sleep(ms(1500));
1392 select! {
1393 recv(r) -> v => assert_eq!(v, Ok(7)),
1394 }
1395 select! {
1396 recv(r) -> v => assert_eq!(v, Ok(8)),
1397 }
1398 select! {
1399 recv(r) -> v => assert_eq!(v, Ok(9)),
1400 }
1401 });
1402 })
1403 .unwrap();
1404 }
1405
1406 #[test]
send_timeout()1407 fn send_timeout() {
1408 let (s, r) = bounded(0);
1409
1410 scope(|scope| {
1411 scope.spawn(move |_| {
1412 select! {
1413 send(s, 7) -> _ => panic!(),
1414 default(ms(1000)) => {}
1415 }
1416 select! {
1417 send(s, 8) -> res => res.unwrap(),
1418 default(ms(1000)) => panic!(),
1419 }
1420 select! {
1421 send(s, 9) -> res => assert_eq!(res, Err(SendError(9))),
1422 default(ms(1000)) => panic!(),
1423 }
1424 });
1425 scope.spawn(move |_| {
1426 thread::sleep(ms(1500));
1427 select! {
1428 recv(r) -> v => assert_eq!(v, Ok(8)),
1429 }
1430 });
1431 })
1432 .unwrap();
1433 }
1434
1435 #[test]
disconnect_wakes_sender()1436 fn disconnect_wakes_sender() {
1437 let (s, r) = bounded(0);
1438
1439 scope(|scope| {
1440 scope.spawn(move |_| {
1441 select! {
1442 send(s, ()) -> res => assert_eq!(res, Err(SendError(()))),
1443 }
1444 });
1445 scope.spawn(move |_| {
1446 thread::sleep(ms(1000));
1447 drop(r);
1448 });
1449 })
1450 .unwrap();
1451 }
1452
1453 #[test]
disconnect_wakes_receiver()1454 fn disconnect_wakes_receiver() {
1455 let (s, r) = bounded::<()>(0);
1456
1457 scope(|scope| {
1458 scope.spawn(move |_| {
1459 select! {
1460 recv(r) -> res => assert_eq!(res, Err(RecvError)),
1461 }
1462 });
1463 scope.spawn(move |_| {
1464 thread::sleep(ms(1000));
1465 drop(s);
1466 });
1467 })
1468 .unwrap();
1469 }
1470
1471 #[test]
trailing_comma()1472 fn trailing_comma() {
1473 let (s, r) = unbounded::<usize>();
1474
1475 select! {
1476 send(s, 1,) -> _ => {},
1477 recv(r,) -> _ => {},
1478 default(ms(1000),) => {},
1479 }
1480 }
1481