1 use std::sync::atomic::{AtomicUsize, Ordering};
2
3 use crossbeam_queue::SegQueue;
4 use crossbeam_utils::thread::scope;
5 use rand::{thread_rng, Rng};
6
7 #[test]
smoke()8 fn smoke() {
9 let q = SegQueue::new();
10 q.push(7);
11 assert_eq!(q.pop(), Some(7));
12
13 q.push(8);
14 assert_eq!(q.pop(), Some(8));
15 assert!(q.pop().is_none());
16 }
17
18 #[test]
len_empty_full()19 fn len_empty_full() {
20 let q = SegQueue::new();
21
22 assert_eq!(q.len(), 0);
23 assert!(q.is_empty());
24
25 q.push(());
26
27 assert_eq!(q.len(), 1);
28 assert!(!q.is_empty());
29
30 q.pop().unwrap();
31
32 assert_eq!(q.len(), 0);
33 assert!(q.is_empty());
34 }
35
36 #[test]
len()37 fn len() {
38 let q = SegQueue::new();
39
40 assert_eq!(q.len(), 0);
41
42 for i in 0..50 {
43 q.push(i);
44 assert_eq!(q.len(), i + 1);
45 }
46
47 for i in 0..50 {
48 q.pop().unwrap();
49 assert_eq!(q.len(), 50 - i - 1);
50 }
51
52 assert_eq!(q.len(), 0);
53 }
54
55 #[cfg_attr(miri, ignore)] // Miri is too slow
56 #[test]
spsc()57 fn spsc() {
58 const COUNT: usize = 100_000;
59
60 let q = SegQueue::new();
61
62 scope(|scope| {
63 scope.spawn(|_| {
64 for i in 0..COUNT {
65 loop {
66 if let Some(x) = q.pop() {
67 assert_eq!(x, i);
68 break;
69 }
70 }
71 }
72 assert!(q.pop().is_none());
73 });
74 scope.spawn(|_| {
75 for i in 0..COUNT {
76 q.push(i);
77 }
78 });
79 })
80 .unwrap();
81 }
82
83 #[cfg_attr(miri, ignore)] // Miri is too slow
84 #[test]
mpmc()85 fn mpmc() {
86 const COUNT: usize = 25_000;
87 const THREADS: usize = 4;
88
89 let q = SegQueue::<usize>::new();
90 let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
91
92 scope(|scope| {
93 for _ in 0..THREADS {
94 scope.spawn(|_| {
95 for _ in 0..COUNT {
96 let n = loop {
97 if let Some(x) = q.pop() {
98 break x;
99 }
100 };
101 v[n].fetch_add(1, Ordering::SeqCst);
102 }
103 });
104 }
105 for _ in 0..THREADS {
106 scope.spawn(|_| {
107 for i in 0..COUNT {
108 q.push(i);
109 }
110 });
111 }
112 })
113 .unwrap();
114
115 for c in v {
116 assert_eq!(c.load(Ordering::SeqCst), THREADS);
117 }
118 }
119
120 #[cfg_attr(miri, ignore)] // Miri is too slow
121 #[test]
drops()122 fn drops() {
123 const RUNS: usize = 100;
124
125 static DROPS: AtomicUsize = AtomicUsize::new(0);
126
127 #[derive(Debug, PartialEq)]
128 struct DropCounter;
129
130 impl Drop for DropCounter {
131 fn drop(&mut self) {
132 DROPS.fetch_add(1, Ordering::SeqCst);
133 }
134 }
135
136 let mut rng = thread_rng();
137
138 for _ in 0..RUNS {
139 let steps = rng.gen_range(0..10_000);
140 let additional = rng.gen_range(0..1000);
141
142 DROPS.store(0, Ordering::SeqCst);
143 let q = SegQueue::new();
144
145 scope(|scope| {
146 scope.spawn(|_| {
147 for _ in 0..steps {
148 while q.pop().is_none() {}
149 }
150 });
151
152 scope.spawn(|_| {
153 for _ in 0..steps {
154 q.push(DropCounter);
155 }
156 });
157 })
158 .unwrap();
159
160 for _ in 0..additional {
161 q.push(DropCounter);
162 }
163
164 assert_eq!(DROPS.load(Ordering::SeqCst), steps);
165 drop(q);
166 assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional);
167 }
168 }
169
170 #[test]
into_iter()171 fn into_iter() {
172 let q = SegQueue::new();
173 for i in 0..100 {
174 q.push(i);
175 }
176 for (i, j) in q.into_iter().enumerate() {
177 assert_eq!(i, j);
178 }
179 }
180
181 #[test]
into_iter_drop()182 fn into_iter_drop() {
183 let q = SegQueue::new();
184 for i in 0..100 {
185 q.push(i);
186 }
187 for (i, j) in q.into_iter().enumerate().take(50) {
188 assert_eq!(i, j);
189 }
190 }
191