]> git.proxmox.com Git - rustc.git/blob - library/std/src/lazy/tests.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / library / std / src / lazy / tests.rs
1 use crate::{
2 lazy::{Lazy, SyncLazy, SyncOnceCell},
3 panic,
4 sync::{
5 atomic::{AtomicUsize, Ordering::SeqCst},
6 mpsc::channel,
7 Mutex,
8 },
9 thread,
10 };
11
12 #[test]
13 fn lazy_default() {
14 static CALLED: AtomicUsize = AtomicUsize::new(0);
15
16 struct Foo(u8);
17 impl Default for Foo {
18 fn default() -> Self {
19 CALLED.fetch_add(1, SeqCst);
20 Foo(42)
21 }
22 }
23
24 let lazy: Lazy<Mutex<Foo>> = <_>::default();
25
26 assert_eq!(CALLED.load(SeqCst), 0);
27
28 assert_eq!(lazy.lock().unwrap().0, 42);
29 assert_eq!(CALLED.load(SeqCst), 1);
30
31 lazy.lock().unwrap().0 = 21;
32
33 assert_eq!(lazy.lock().unwrap().0, 21);
34 assert_eq!(CALLED.load(SeqCst), 1);
35 }
36
37 #[test]
38 fn lazy_poisoning() {
39 let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
40 for _ in 0..2 {
41 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
42 assert!(res.is_err());
43 }
44 }
45
46 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
47 thread::spawn(f).join().unwrap()
48 }
49
50 #[test]
51 fn sync_once_cell() {
52 static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
53
54 assert!(ONCE_CELL.get().is_none());
55
56 spawn_and_wait(|| {
57 ONCE_CELL.get_or_init(|| 92);
58 assert_eq!(ONCE_CELL.get(), Some(&92));
59 });
60
61 ONCE_CELL.get_or_init(|| panic!("Kabom!"));
62 assert_eq!(ONCE_CELL.get(), Some(&92));
63 }
64
65 #[test]
66 fn sync_once_cell_get_mut() {
67 let mut c = SyncOnceCell::new();
68 assert!(c.get_mut().is_none());
69 c.set(90).unwrap();
70 *c.get_mut().unwrap() += 2;
71 assert_eq!(c.get_mut(), Some(&mut 92));
72 }
73
74 #[test]
75 fn sync_once_cell_get_unchecked() {
76 let c = SyncOnceCell::new();
77 c.set(92).unwrap();
78 unsafe {
79 assert_eq!(c.get_unchecked(), &92);
80 }
81 }
82
83 #[test]
84 fn sync_once_cell_drop() {
85 static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
86 struct Dropper;
87 impl Drop for Dropper {
88 fn drop(&mut self) {
89 DROP_CNT.fetch_add(1, SeqCst);
90 }
91 }
92
93 let x = SyncOnceCell::new();
94 spawn_and_wait(move || {
95 x.get_or_init(|| Dropper);
96 assert_eq!(DROP_CNT.load(SeqCst), 0);
97 drop(x);
98 });
99
100 assert_eq!(DROP_CNT.load(SeqCst), 1);
101 }
102
103 #[test]
104 fn sync_once_cell_drop_empty() {
105 let x = SyncOnceCell::<String>::new();
106 drop(x);
107 }
108
109 #[test]
110 fn clone() {
111 let s = SyncOnceCell::new();
112 let c = s.clone();
113 assert!(c.get().is_none());
114
115 s.set("hello".to_string()).unwrap();
116 let c = s.clone();
117 assert_eq!(c.get().map(String::as_str), Some("hello"));
118 }
119
120 #[test]
121 fn get_or_try_init() {
122 let cell: SyncOnceCell<String> = SyncOnceCell::new();
123 assert!(cell.get().is_none());
124
125 let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
126 assert!(res.is_err());
127 assert!(!cell.is_initialized());
128 assert!(cell.get().is_none());
129
130 assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
131
132 assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string()));
133 assert_eq!(cell.get(), Some(&"hello".to_string()));
134 }
135
136 #[test]
137 fn from_impl() {
138 assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
139 assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
140 }
141
142 #[test]
143 fn partialeq_impl() {
144 assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
145 assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
146
147 assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
148 assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
149 }
150
151 #[test]
152 fn into_inner() {
153 let cell: SyncOnceCell<String> = SyncOnceCell::new();
154 assert_eq!(cell.into_inner(), None);
155 let cell = SyncOnceCell::new();
156 cell.set("hello".to_string()).unwrap();
157 assert_eq!(cell.into_inner(), Some("hello".to_string()));
158 }
159
160 #[test]
161 fn sync_lazy_new() {
162 static CALLED: AtomicUsize = AtomicUsize::new(0);
163 static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
164 CALLED.fetch_add(1, SeqCst);
165 92
166 });
167
168 assert_eq!(CALLED.load(SeqCst), 0);
169
170 spawn_and_wait(|| {
171 let y = *SYNC_LAZY - 30;
172 assert_eq!(y, 62);
173 assert_eq!(CALLED.load(SeqCst), 1);
174 });
175
176 let y = *SYNC_LAZY - 30;
177 assert_eq!(y, 62);
178 assert_eq!(CALLED.load(SeqCst), 1);
179 }
180
181 #[test]
182 fn sync_lazy_default() {
183 static CALLED: AtomicUsize = AtomicUsize::new(0);
184
185 struct Foo(u8);
186 impl Default for Foo {
187 fn default() -> Self {
188 CALLED.fetch_add(1, SeqCst);
189 Foo(42)
190 }
191 }
192
193 let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
194
195 assert_eq!(CALLED.load(SeqCst), 0);
196
197 assert_eq!(lazy.lock().unwrap().0, 42);
198 assert_eq!(CALLED.load(SeqCst), 1);
199
200 lazy.lock().unwrap().0 = 21;
201
202 assert_eq!(lazy.lock().unwrap().0, 21);
203 assert_eq!(CALLED.load(SeqCst), 1);
204 }
205
206 #[test]
207 fn static_sync_lazy() {
208 static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
209 let mut xs = Vec::new();
210 xs.push(1);
211 xs.push(2);
212 xs.push(3);
213 xs
214 });
215
216 spawn_and_wait(|| {
217 assert_eq!(&*XS, &vec![1, 2, 3]);
218 });
219
220 assert_eq!(&*XS, &vec![1, 2, 3]);
221 }
222
223 #[test]
224 fn static_sync_lazy_via_fn() {
225 fn xs() -> &'static Vec<i32> {
226 static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
227 XS.get_or_init(|| {
228 let mut xs = Vec::new();
229 xs.push(1);
230 xs.push(2);
231 xs.push(3);
232 xs
233 })
234 }
235 assert_eq!(xs(), &vec![1, 2, 3]);
236 }
237
238 #[test]
239 fn sync_lazy_poisoning() {
240 let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
241 for _ in 0..2 {
242 let res = panic::catch_unwind(|| x.len());
243 assert!(res.is_err());
244 }
245 }
246
247 #[test]
248 fn is_sync_send() {
249 fn assert_traits<T: Send + Sync>() {}
250 assert_traits::<SyncOnceCell<String>>();
251 assert_traits::<SyncLazy<String>>();
252 }
253
254 #[test]
255 fn eval_once_macro() {
256 macro_rules! eval_once {
257 (|| -> $ty:ty {
258 $($body:tt)*
259 }) => {{
260 static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
261 fn init() -> $ty {
262 $($body)*
263 }
264 ONCE_CELL.get_or_init(init)
265 }};
266 }
267
268 let fib: &'static Vec<i32> = eval_once! {
269 || -> Vec<i32> {
270 let mut res = vec![1, 1];
271 for i in 0..10 {
272 let next = res[i] + res[i + 1];
273 res.push(next);
274 }
275 res
276 }
277 };
278 assert_eq!(fib[5], 8)
279 }
280
281 #[test]
282 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
283 static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
284
285 let n_readers = 10;
286 let n_writers = 3;
287 const MSG: &str = "Hello, World";
288
289 let (tx, rx) = channel();
290
291 for _ in 0..n_readers {
292 let tx = tx.clone();
293 thread::spawn(move || {
294 loop {
295 if let Some(msg) = ONCE_CELL.get() {
296 tx.send(msg).unwrap();
297 break;
298 }
299 #[cfg(target_env = "sgx")]
300 crate::thread::yield_now();
301 }
302 });
303 }
304 for _ in 0..n_writers {
305 thread::spawn(move || {
306 let _ = ONCE_CELL.set(MSG.to_owned());
307 });
308 }
309
310 for _ in 0..n_readers {
311 let msg = rx.recv().unwrap();
312 assert_eq!(msg, MSG);
313 }
314 }
315
316 #[test]
317 fn dropck() {
318 let cell = SyncOnceCell::new();
319 {
320 let s = String::new();
321 cell.set(&s).unwrap();
322 }
323 }