1 | #![warn (rust_2018_idioms)] |
2 | #![cfg (feature = "full" )] |
3 | |
4 | use std::mem; |
5 | use std::ops::Drop; |
6 | use std::sync::atomic::{AtomicU32, Ordering}; |
7 | use std::time::Duration; |
8 | use tokio::runtime; |
9 | use tokio::sync::OnceCell; |
10 | use tokio::sync::SetError; |
11 | use tokio::time; |
12 | |
13 | #[test] |
14 | fn drop_cell() { |
15 | static NUM_DROPS: AtomicU32 = AtomicU32::new(0); |
16 | |
17 | struct Foo {} |
18 | |
19 | let fooer = Foo {}; |
20 | |
21 | impl Drop for Foo { |
22 | fn drop(&mut self) { |
23 | NUM_DROPS.fetch_add(1, Ordering::Release); |
24 | } |
25 | } |
26 | |
27 | { |
28 | let once_cell = OnceCell::new(); |
29 | let prev = once_cell.set(fooer); |
30 | assert!(prev.is_ok()) |
31 | } |
32 | assert!(NUM_DROPS.load(Ordering::Acquire) == 1); |
33 | } |
34 | |
35 | #[test] |
36 | fn drop_cell_new_with() { |
37 | static NUM_DROPS: AtomicU32 = AtomicU32::new(0); |
38 | |
39 | struct Foo {} |
40 | |
41 | let fooer = Foo {}; |
42 | |
43 | impl Drop for Foo { |
44 | fn drop(&mut self) { |
45 | NUM_DROPS.fetch_add(1, Ordering::Release); |
46 | } |
47 | } |
48 | |
49 | { |
50 | let once_cell = OnceCell::new_with(Some(fooer)); |
51 | assert!(once_cell.initialized()); |
52 | } |
53 | assert!(NUM_DROPS.load(Ordering::Acquire) == 1); |
54 | } |
55 | |
56 | #[test] |
57 | fn drop_into_inner() { |
58 | static NUM_DROPS: AtomicU32 = AtomicU32::new(0); |
59 | |
60 | struct Foo {} |
61 | |
62 | let fooer = Foo {}; |
63 | |
64 | impl Drop for Foo { |
65 | fn drop(&mut self) { |
66 | NUM_DROPS.fetch_add(1, Ordering::Release); |
67 | } |
68 | } |
69 | |
70 | let once_cell = OnceCell::new(); |
71 | assert!(once_cell.set(fooer).is_ok()); |
72 | let fooer = once_cell.into_inner(); |
73 | let count = NUM_DROPS.load(Ordering::Acquire); |
74 | assert!(count == 0); |
75 | drop(fooer); |
76 | let count = NUM_DROPS.load(Ordering::Acquire); |
77 | assert!(count == 1); |
78 | } |
79 | |
80 | #[test] |
81 | fn drop_into_inner_new_with() { |
82 | static NUM_DROPS: AtomicU32 = AtomicU32::new(0); |
83 | |
84 | struct Foo {} |
85 | |
86 | let fooer = Foo {}; |
87 | |
88 | impl Drop for Foo { |
89 | fn drop(&mut self) { |
90 | NUM_DROPS.fetch_add(1, Ordering::Release); |
91 | } |
92 | } |
93 | |
94 | let once_cell = OnceCell::new_with(Some(fooer)); |
95 | let fooer = once_cell.into_inner(); |
96 | let count = NUM_DROPS.load(Ordering::Acquire); |
97 | assert!(count == 0); |
98 | mem::drop(fooer); |
99 | let count = NUM_DROPS.load(Ordering::Acquire); |
100 | assert!(count == 1); |
101 | } |
102 | |
103 | #[test] |
104 | fn from() { |
105 | let cell = OnceCell::from(2); |
106 | assert_eq!(*cell.get().unwrap(), 2); |
107 | } |
108 | |
109 | async fn func1() -> u32 { |
110 | 5 |
111 | } |
112 | |
113 | async fn func2() -> u32 { |
114 | time::sleep(Duration::from_millis(1)).await; |
115 | 10 |
116 | } |
117 | |
118 | async fn func_err() -> Result<u32, ()> { |
119 | Err(()) |
120 | } |
121 | |
122 | async fn func_ok() -> Result<u32, ()> { |
123 | Ok(10) |
124 | } |
125 | |
126 | async fn func_panic() -> u32 { |
127 | time::sleep(Duration::from_millis(1)).await; |
128 | panic!(); |
129 | } |
130 | |
131 | async fn sleep_and_set() -> u32 { |
132 | // Simulate sleep by pausing time and waiting for another thread to |
133 | // resume clock when calling `set`, then finding the cell being initialized |
134 | // by this call |
135 | time::sleep(Duration::from_millis(2)).await; |
136 | 5 |
137 | } |
138 | |
139 | async fn advance_time_and_set(cell: &'static OnceCell<u32>, v: u32) -> Result<(), SetError<u32>> { |
140 | time::advance(Duration::from_millis(1)).await; |
141 | cell.set(v) |
142 | } |
143 | |
144 | #[test] |
145 | fn get_or_init() { |
146 | let rt = runtime::Builder::new_current_thread() |
147 | .enable_time() |
148 | .start_paused(true) |
149 | .build() |
150 | .unwrap(); |
151 | |
152 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
153 | |
154 | rt.block_on(async { |
155 | let handle1 = rt.spawn(async { ONCE.get_or_init(func1).await }); |
156 | let handle2 = rt.spawn(async { ONCE.get_or_init(func2).await }); |
157 | |
158 | time::advance(Duration::from_millis(1)).await; |
159 | time::resume(); |
160 | |
161 | let result1 = handle1.await.unwrap(); |
162 | let result2 = handle2.await.unwrap(); |
163 | |
164 | assert_eq!(*result1, 5); |
165 | assert_eq!(*result2, 5); |
166 | }); |
167 | } |
168 | |
169 | #[test] |
170 | fn get_or_init_panic() { |
171 | let rt = runtime::Builder::new_current_thread() |
172 | .enable_time() |
173 | .build() |
174 | .unwrap(); |
175 | |
176 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
177 | |
178 | rt.block_on(async { |
179 | time::pause(); |
180 | |
181 | let handle1 = rt.spawn(async { ONCE.get_or_init(func1).await }); |
182 | let handle2 = rt.spawn(async { ONCE.get_or_init(func_panic).await }); |
183 | |
184 | time::advance(Duration::from_millis(1)).await; |
185 | |
186 | let result1 = handle1.await.unwrap(); |
187 | let result2 = handle2.await.unwrap(); |
188 | |
189 | assert_eq!(*result1, 5); |
190 | assert_eq!(*result2, 5); |
191 | }); |
192 | } |
193 | |
194 | #[test] |
195 | fn set_and_get() { |
196 | let rt = runtime::Builder::new_current_thread() |
197 | .enable_time() |
198 | .build() |
199 | .unwrap(); |
200 | |
201 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
202 | |
203 | rt.block_on(async { |
204 | let _ = rt.spawn(async { ONCE.set(5) }).await; |
205 | let value = ONCE.get().unwrap(); |
206 | assert_eq!(*value, 5); |
207 | }); |
208 | } |
209 | |
210 | #[test] |
211 | fn get_uninit() { |
212 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
213 | let uninit = ONCE.get(); |
214 | assert!(uninit.is_none()); |
215 | } |
216 | |
217 | #[test] |
218 | fn set_twice() { |
219 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
220 | |
221 | let first = ONCE.set(5); |
222 | assert_eq!(first, Ok(())); |
223 | let second = ONCE.set(6); |
224 | assert!(second.err().unwrap().is_already_init_err()); |
225 | } |
226 | |
227 | #[test] |
228 | fn set_while_initializing() { |
229 | let rt = runtime::Builder::new_current_thread() |
230 | .enable_time() |
231 | .build() |
232 | .unwrap(); |
233 | |
234 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
235 | |
236 | rt.block_on(async { |
237 | time::pause(); |
238 | |
239 | let handle1 = rt.spawn(async { ONCE.get_or_init(sleep_and_set).await }); |
240 | let handle2 = rt.spawn(async { advance_time_and_set(&ONCE, 10).await }); |
241 | |
242 | time::advance(Duration::from_millis(2)).await; |
243 | |
244 | let result1 = handle1.await.unwrap(); |
245 | let result2 = handle2.await.unwrap(); |
246 | |
247 | assert_eq!(*result1, 5); |
248 | assert!(result2.err().unwrap().is_initializing_err()); |
249 | }); |
250 | } |
251 | |
252 | #[test] |
253 | fn get_or_try_init() { |
254 | let rt = runtime::Builder::new_current_thread() |
255 | .enable_time() |
256 | .start_paused(true) |
257 | .build() |
258 | .unwrap(); |
259 | |
260 | static ONCE: OnceCell<u32> = OnceCell::const_new(); |
261 | |
262 | rt.block_on(async { |
263 | let handle1 = rt.spawn(async { ONCE.get_or_try_init(func_err).await }); |
264 | let handle2 = rt.spawn(async { ONCE.get_or_try_init(func_ok).await }); |
265 | |
266 | time::advance(Duration::from_millis(1)).await; |
267 | time::resume(); |
268 | |
269 | let result1 = handle1.await.unwrap(); |
270 | assert!(result1.is_err()); |
271 | |
272 | let result2 = handle2.await.unwrap(); |
273 | assert_eq!(*result2.unwrap(), 10); |
274 | }); |
275 | } |
276 | |