]> git.proxmox.com Git - rustc.git/blob - vendor/once_cell/tests/it.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / vendor / once_cell / tests / it.rs
1 mod unsync {
2 use core::{
3 cell::Cell,
4 sync::atomic::{AtomicUsize, Ordering::SeqCst},
5 };
6
7 use once_cell::unsync::{Lazy, OnceCell};
8
9 #[test]
10 fn once_cell() {
11 let c = OnceCell::new();
12 assert!(c.get().is_none());
13 c.get_or_init(|| 92);
14 assert_eq!(c.get(), Some(&92));
15
16 c.get_or_init(|| panic!("Kabom!"));
17 assert_eq!(c.get(), Some(&92));
18 }
19
20 #[test]
21 fn once_cell_with_value() {
22 const CELL: OnceCell<i32> = OnceCell::with_value(12);
23 let cell = CELL;
24 assert_eq!(cell.get(), Some(&12));
25 }
26
27 #[test]
28 fn once_cell_get_mut() {
29 let mut c = OnceCell::new();
30 assert!(c.get_mut().is_none());
31 c.set(90).unwrap();
32 *c.get_mut().unwrap() += 2;
33 assert_eq!(c.get_mut(), Some(&mut 92));
34 }
35
36 #[test]
37 fn once_cell_drop() {
38 static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
39 struct Dropper;
40 impl Drop for Dropper {
41 fn drop(&mut self) {
42 DROP_CNT.fetch_add(1, SeqCst);
43 }
44 }
45
46 let x = OnceCell::new();
47 x.get_or_init(|| Dropper);
48 assert_eq!(DROP_CNT.load(SeqCst), 0);
49 drop(x);
50 assert_eq!(DROP_CNT.load(SeqCst), 1);
51 }
52
53 #[test]
54 fn unsync_once_cell_drop_empty() {
55 let x = OnceCell::<String>::new();
56 drop(x);
57 }
58
59 #[test]
60 fn clone() {
61 let s = OnceCell::new();
62 let c = s.clone();
63 assert!(c.get().is_none());
64
65 s.set("hello".to_string()).unwrap();
66 let c = s.clone();
67 assert_eq!(c.get().map(String::as_str), Some("hello"));
68 }
69
70 #[test]
71 fn from_impl() {
72 assert_eq!(OnceCell::from("value").get(), Some(&"value"));
73 assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
74 }
75
76 #[test]
77 fn partialeq_impl() {
78 assert!(OnceCell::from("value") == OnceCell::from("value"));
79 assert!(OnceCell::from("foo") != OnceCell::from("bar"));
80
81 assert!(OnceCell::<String>::new() == OnceCell::new());
82 assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
83 }
84
85 #[test]
86 fn into_inner() {
87 let cell: OnceCell<String> = OnceCell::new();
88 assert_eq!(cell.into_inner(), None);
89 let cell = OnceCell::new();
90 cell.set("hello".to_string()).unwrap();
91 assert_eq!(cell.into_inner(), Some("hello".to_string()));
92 }
93
94 #[test]
95 fn debug_impl() {
96 let cell = OnceCell::new();
97 assert_eq!(format!("{:?}", cell), "OnceCell(Uninit)");
98 cell.set("hello".to_string()).unwrap();
99 assert_eq!(format!("{:?}", cell), "OnceCell(\"hello\")");
100 }
101
102 #[test]
103 fn lazy_new() {
104 let called = Cell::new(0);
105 let x = Lazy::new(|| {
106 called.set(called.get() + 1);
107 92
108 });
109
110 assert_eq!(called.get(), 0);
111
112 let y = *x - 30;
113 assert_eq!(y, 62);
114 assert_eq!(called.get(), 1);
115
116 let y = *x - 30;
117 assert_eq!(y, 62);
118 assert_eq!(called.get(), 1);
119 }
120
121 #[test]
122 fn lazy_deref_mut() {
123 let called = Cell::new(0);
124 let mut x = Lazy::new(|| {
125 called.set(called.get() + 1);
126 92
127 });
128
129 assert_eq!(called.get(), 0);
130
131 let y = *x - 30;
132 assert_eq!(y, 62);
133 assert_eq!(called.get(), 1);
134
135 *x /= 2;
136 assert_eq!(*x, 46);
137 assert_eq!(called.get(), 1);
138 }
139
140 #[test]
141 fn lazy_default() {
142 static CALLED: AtomicUsize = AtomicUsize::new(0);
143
144 struct Foo(u8);
145 impl Default for Foo {
146 fn default() -> Self {
147 CALLED.fetch_add(1, SeqCst);
148 Foo(42)
149 }
150 }
151
152 let lazy: Lazy<std::sync::Mutex<Foo>> = <_>::default();
153
154 assert_eq!(CALLED.load(SeqCst), 0);
155
156 assert_eq!(lazy.lock().unwrap().0, 42);
157 assert_eq!(CALLED.load(SeqCst), 1);
158
159 lazy.lock().unwrap().0 = 21;
160
161 assert_eq!(lazy.lock().unwrap().0, 21);
162 assert_eq!(CALLED.load(SeqCst), 1);
163 }
164
165 #[test]
166 fn lazy_into_value() {
167 let l: Lazy<i32, _> = Lazy::new(|| panic!());
168 assert!(matches!(Lazy::into_value(l), Err(_)));
169 let l = Lazy::new(|| -> i32 { 92 });
170 Lazy::force(&l);
171 assert!(matches!(Lazy::into_value(l), Ok(92)));
172 }
173
174 #[test]
175 #[cfg(feature = "std")]
176 fn lazy_poisoning() {
177 let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
178 for _ in 0..2 {
179 let res = std::panic::catch_unwind(|| x.len());
180 assert!(res.is_err());
181 }
182 }
183
184 #[test]
185 fn aliasing_in_get() {
186 let x = OnceCell::new();
187 x.set(42).unwrap();
188 let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
189 let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
190 println!("{}", at_x); // <------- up until here ---------------------------+
191 }
192
193 #[test]
194 #[should_panic(expected = "reentrant init")]
195 fn reentrant_init() {
196 let x: OnceCell<Box<i32>> = OnceCell::new();
197 let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
198 x.get_or_init(|| {
199 let r = x.get_or_init(|| Box::new(92));
200 dangling_ref.set(Some(r));
201 Box::new(62)
202 });
203 eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
204 }
205
206 #[test]
207 // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
208 fn arrrrrrrrrrrrrrrrrrrrrr() {
209 let cell = OnceCell::new();
210 {
211 let s = String::new();
212 cell.set(&s).unwrap();
213 }
214 }
215 }
216
217 #[cfg(feature = "std")]
218 mod sync {
219 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
220
221 use crossbeam_utils::thread::scope;
222
223 use once_cell::sync::{Lazy, OnceCell};
224
225 #[test]
226 fn once_cell() {
227 let c = OnceCell::new();
228 assert!(c.get().is_none());
229 scope(|s| {
230 s.spawn(|_| {
231 c.get_or_init(|| 92);
232 assert_eq!(c.get(), Some(&92));
233 });
234 })
235 .unwrap();
236 c.get_or_init(|| panic!("Kabom!"));
237 assert_eq!(c.get(), Some(&92));
238 }
239
240 #[test]
241 fn once_cell_with_value() {
242 static CELL: OnceCell<i32> = OnceCell::with_value(12);
243 assert_eq!(CELL.get(), Some(&12));
244 }
245
246 #[test]
247 fn once_cell_get_mut() {
248 let mut c = OnceCell::new();
249 assert!(c.get_mut().is_none());
250 c.set(90).unwrap();
251 *c.get_mut().unwrap() += 2;
252 assert_eq!(c.get_mut(), Some(&mut 92));
253 }
254
255 #[test]
256 fn once_cell_get_unchecked() {
257 let c = OnceCell::new();
258 c.set(92).unwrap();
259 unsafe {
260 assert_eq!(c.get_unchecked(), &92);
261 }
262 }
263
264 #[test]
265 fn once_cell_drop() {
266 static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
267 struct Dropper;
268 impl Drop for Dropper {
269 fn drop(&mut self) {
270 DROP_CNT.fetch_add(1, SeqCst);
271 }
272 }
273
274 let x = OnceCell::new();
275 scope(|s| {
276 s.spawn(|_| {
277 x.get_or_init(|| Dropper);
278 assert_eq!(DROP_CNT.load(SeqCst), 0);
279 drop(x);
280 });
281 })
282 .unwrap();
283 assert_eq!(DROP_CNT.load(SeqCst), 1);
284 }
285
286 #[test]
287 fn once_cell_drop_empty() {
288 let x = OnceCell::<String>::new();
289 drop(x);
290 }
291
292 #[test]
293 fn clone() {
294 let s = OnceCell::new();
295 let c = s.clone();
296 assert!(c.get().is_none());
297
298 s.set("hello".to_string()).unwrap();
299 let c = s.clone();
300 assert_eq!(c.get().map(String::as_str), Some("hello"));
301 }
302
303 #[test]
304 fn get_or_try_init() {
305 let cell: OnceCell<String> = OnceCell::new();
306 assert!(cell.get().is_none());
307
308 let res =
309 std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
310 assert!(res.is_err());
311 assert!(cell.get().is_none());
312
313 assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
314
315 assert_eq!(
316 cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
317 Ok(&"hello".to_string())
318 );
319 assert_eq!(cell.get(), Some(&"hello".to_string()));
320 }
321
322 #[test]
323 fn wait() {
324 let cell: OnceCell<String> = OnceCell::new();
325 scope(|s| {
326 s.spawn(|_| cell.set("hello".to_string()));
327 let greeting = cell.wait();
328 assert_eq!(greeting, "hello")
329 })
330 .unwrap();
331 }
332
333 #[test]
334 #[cfg_attr(miri, ignore)] // miri doesn't support Barrier
335 fn get_or_init_stress() {
336 use std::sync::Barrier;
337 let n_threads = 1_000;
338 let n_cells = 1_000;
339 let cells: Vec<_> = std::iter::repeat_with(|| (Barrier::new(n_threads), OnceCell::new()))
340 .take(n_cells)
341 .collect();
342 scope(|s| {
343 for t in 0..n_threads {
344 let cells = &cells;
345 s.spawn(move |_| {
346 for (i, (b, s)) in cells.iter().enumerate() {
347 b.wait();
348 let j = if t % 2 == 0 { s.wait() } else { s.get_or_init(|| i) };
349 assert_eq!(*j, i);
350 }
351 });
352 }
353 })
354 .unwrap();
355 }
356
357 #[test]
358 fn from_impl() {
359 assert_eq!(OnceCell::from("value").get(), Some(&"value"));
360 assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
361 }
362
363 #[test]
364 fn partialeq_impl() {
365 assert!(OnceCell::from("value") == OnceCell::from("value"));
366 assert!(OnceCell::from("foo") != OnceCell::from("bar"));
367
368 assert!(OnceCell::<String>::new() == OnceCell::new());
369 assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
370 }
371
372 #[test]
373 fn into_inner() {
374 let cell: OnceCell<String> = OnceCell::new();
375 assert_eq!(cell.into_inner(), None);
376 let cell = OnceCell::new();
377 cell.set("hello".to_string()).unwrap();
378 assert_eq!(cell.into_inner(), Some("hello".to_string()));
379 }
380
381 #[test]
382 fn debug_impl() {
383 let cell = OnceCell::new();
384 assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)");
385 cell.set(vec!["hello", "world"]).unwrap();
386 assert_eq!(
387 format!("{:#?}", cell),
388 r#"OnceCell(
389 [
390 "hello",
391 "world",
392 ],
393 )"#
394 );
395 }
396
397 #[test]
398 #[cfg_attr(miri, ignore)] // miri doesn't support processes
399 fn reentrant_init() {
400 let examples_dir = {
401 let mut exe = std::env::current_exe().unwrap();
402 exe.pop();
403 exe.pop();
404 exe.push("examples");
405 exe
406 };
407 let bin = examples_dir
408 .join("reentrant_init_deadlocks")
409 .with_extension(std::env::consts::EXE_EXTENSION);
410 let mut guard = Guard { child: std::process::Command::new(bin).spawn().unwrap() };
411 std::thread::sleep(std::time::Duration::from_secs(2));
412 let status = guard.child.try_wait().unwrap();
413 assert!(status.is_none());
414
415 struct Guard {
416 child: std::process::Child,
417 }
418
419 impl Drop for Guard {
420 fn drop(&mut self) {
421 let _ = self.child.kill();
422 }
423 }
424 }
425
426 #[test]
427 fn lazy_new() {
428 let called = AtomicUsize::new(0);
429 let x = Lazy::new(|| {
430 called.fetch_add(1, SeqCst);
431 92
432 });
433
434 assert_eq!(called.load(SeqCst), 0);
435
436 scope(|s| {
437 s.spawn(|_| {
438 let y = *x - 30;
439 assert_eq!(y, 62);
440 assert_eq!(called.load(SeqCst), 1);
441 });
442 })
443 .unwrap();
444
445 let y = *x - 30;
446 assert_eq!(y, 62);
447 assert_eq!(called.load(SeqCst), 1);
448 }
449
450 #[test]
451 fn lazy_deref_mut() {
452 let called = AtomicUsize::new(0);
453 let mut x = Lazy::new(|| {
454 called.fetch_add(1, SeqCst);
455 92
456 });
457
458 assert_eq!(called.load(SeqCst), 0);
459
460 let y = *x - 30;
461 assert_eq!(y, 62);
462 assert_eq!(called.load(SeqCst), 1);
463
464 *x /= 2;
465 assert_eq!(*x, 46);
466 assert_eq!(called.load(SeqCst), 1);
467 }
468
469 #[test]
470 fn lazy_default() {
471 static CALLED: AtomicUsize = AtomicUsize::new(0);
472
473 struct Foo(u8);
474 impl Default for Foo {
475 fn default() -> Self {
476 CALLED.fetch_add(1, SeqCst);
477 Foo(42)
478 }
479 }
480
481 let lazy: Lazy<std::sync::Mutex<Foo>> = <_>::default();
482
483 assert_eq!(CALLED.load(SeqCst), 0);
484
485 assert_eq!(lazy.lock().unwrap().0, 42);
486 assert_eq!(CALLED.load(SeqCst), 1);
487
488 lazy.lock().unwrap().0 = 21;
489
490 assert_eq!(lazy.lock().unwrap().0, 21);
491 assert_eq!(CALLED.load(SeqCst), 1);
492 }
493
494 #[test]
495 fn static_lazy() {
496 static XS: Lazy<Vec<i32>> = Lazy::new(|| {
497 let mut xs = Vec::new();
498 xs.push(1);
499 xs.push(2);
500 xs.push(3);
501 xs
502 });
503 scope(|s| {
504 s.spawn(|_| {
505 assert_eq!(&*XS, &vec![1, 2, 3]);
506 });
507 })
508 .unwrap();
509 assert_eq!(&*XS, &vec![1, 2, 3]);
510 }
511
512 #[test]
513 fn static_lazy_via_fn() {
514 fn xs() -> &'static Vec<i32> {
515 static XS: OnceCell<Vec<i32>> = OnceCell::new();
516 XS.get_or_init(|| {
517 let mut xs = Vec::new();
518 xs.push(1);
519 xs.push(2);
520 xs.push(3);
521 xs
522 })
523 }
524 assert_eq!(xs(), &vec![1, 2, 3]);
525 }
526
527 #[test]
528 fn lazy_into_value() {
529 let l: Lazy<i32, _> = Lazy::new(|| panic!());
530 assert!(matches!(Lazy::into_value(l), Err(_)));
531 let l = Lazy::new(|| -> i32 { 92 });
532 Lazy::force(&l);
533 assert!(matches!(Lazy::into_value(l), Ok(92)));
534 }
535
536 #[test]
537 fn lazy_poisoning() {
538 let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
539 for _ in 0..2 {
540 let res = std::panic::catch_unwind(|| x.len());
541 assert!(res.is_err());
542 }
543 }
544
545 #[test]
546 fn once_cell_is_sync_send() {
547 fn assert_traits<T: Send + Sync>() {}
548 assert_traits::<OnceCell<String>>();
549 assert_traits::<Lazy<String>>();
550 }
551
552 #[test]
553 fn eval_once_macro() {
554 macro_rules! eval_once {
555 (|| -> $ty:ty {
556 $($body:tt)*
557 }) => {{
558 static ONCE_CELL: OnceCell<$ty> = OnceCell::new();
559 fn init() -> $ty {
560 $($body)*
561 }
562 ONCE_CELL.get_or_init(init)
563 }};
564 }
565
566 let fib: &'static Vec<i32> = eval_once! {
567 || -> Vec<i32> {
568 let mut res = vec![1, 1];
569 for i in 0..10 {
570 let next = res[i] + res[i + 1];
571 res.push(next);
572 }
573 res
574 }
575 };
576 assert_eq!(fib[5], 8)
577 }
578
579 #[test]
580 #[cfg_attr(miri, ignore)] // FIXME: deadlocks, likely caused by https://github.com/rust-lang/miri/issues/1388
581 fn once_cell_does_not_leak_partially_constructed_boxes() {
582 let n_tries = 100;
583 let n_readers = 10;
584 let n_writers = 3;
585 const MSG: &str = "Hello, World";
586
587 for _ in 0..n_tries {
588 let cell: OnceCell<String> = OnceCell::new();
589 scope(|scope| {
590 for _ in 0..n_readers {
591 scope.spawn(|_| loop {
592 if let Some(msg) = cell.get() {
593 assert_eq!(msg, MSG);
594 break;
595 }
596 });
597 }
598 for _ in 0..n_writers {
599 let _ = scope.spawn(|_| cell.set(MSG.to_owned()));
600 }
601 })
602 .unwrap()
603 }
604 }
605
606 #[test]
607 #[cfg_attr(miri, ignore)] // miri doesn't support Barrier
608 fn get_does_not_block() {
609 use std::sync::Barrier;
610
611 let cell = OnceCell::new();
612 let barrier = Barrier::new(2);
613 scope(|scope| {
614 scope.spawn(|_| {
615 cell.get_or_init(|| {
616 barrier.wait();
617 barrier.wait();
618 "hello".to_string()
619 });
620 });
621 barrier.wait();
622 assert_eq!(cell.get(), None);
623 barrier.wait();
624 })
625 .unwrap();
626 assert_eq!(cell.get(), Some(&"hello".to_string()));
627 }
628
629 #[test]
630 // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
631 fn arrrrrrrrrrrrrrrrrrrrrr() {
632 let cell = OnceCell::new();
633 {
634 let s = String::new();
635 cell.set(&s).unwrap();
636 }
637 }
638 }
639
640 #[cfg(feature = "race")]
641 mod race {
642 use std::{
643 num::NonZeroUsize,
644 sync::{
645 atomic::{AtomicUsize, Ordering::SeqCst},
646 Barrier,
647 },
648 };
649
650 use crossbeam_utils::thread::scope;
651
652 use once_cell::race::{OnceBool, OnceNonZeroUsize};
653
654 #[test]
655 fn once_non_zero_usize_smoke_test() {
656 let cnt = AtomicUsize::new(0);
657 let cell = OnceNonZeroUsize::new();
658 let val = NonZeroUsize::new(92).unwrap();
659 scope(|s| {
660 s.spawn(|_| {
661 assert_eq!(
662 cell.get_or_init(|| {
663 cnt.fetch_add(1, SeqCst);
664 val
665 }),
666 val
667 );
668 assert_eq!(cnt.load(SeqCst), 1);
669
670 assert_eq!(
671 cell.get_or_init(|| {
672 cnt.fetch_add(1, SeqCst);
673 val
674 }),
675 val
676 );
677 assert_eq!(cnt.load(SeqCst), 1);
678 });
679 })
680 .unwrap();
681 assert_eq!(cell.get(), Some(val));
682 assert_eq!(cnt.load(SeqCst), 1);
683 }
684
685 #[test]
686 fn once_non_zero_usize_set() {
687 let val1 = NonZeroUsize::new(92).unwrap();
688 let val2 = NonZeroUsize::new(62).unwrap();
689
690 let cell = OnceNonZeroUsize::new();
691
692 assert!(cell.set(val1).is_ok());
693 assert_eq!(cell.get(), Some(val1));
694
695 assert!(cell.set(val2).is_err());
696 assert_eq!(cell.get(), Some(val1));
697 }
698
699 #[test]
700 fn once_non_zero_usize_first_wins() {
701 let val1 = NonZeroUsize::new(92).unwrap();
702 let val2 = NonZeroUsize::new(62).unwrap();
703
704 let cell = OnceNonZeroUsize::new();
705
706 let b1 = Barrier::new(2);
707 let b2 = Barrier::new(2);
708 let b3 = Barrier::new(2);
709 scope(|s| {
710 s.spawn(|_| {
711 let r1 = cell.get_or_init(|| {
712 b1.wait();
713 b2.wait();
714 val1
715 });
716 assert_eq!(r1, val1);
717 b3.wait();
718 });
719 b1.wait();
720 s.spawn(|_| {
721 let r2 = cell.get_or_init(|| {
722 b2.wait();
723 b3.wait();
724 val2
725 });
726 assert_eq!(r2, val1);
727 });
728 })
729 .unwrap();
730
731 assert_eq!(cell.get(), Some(val1));
732 }
733
734 #[test]
735 fn once_bool_smoke_test() {
736 let cnt = AtomicUsize::new(0);
737 let cell = OnceBool::new();
738 scope(|s| {
739 s.spawn(|_| {
740 assert_eq!(
741 cell.get_or_init(|| {
742 cnt.fetch_add(1, SeqCst);
743 false
744 }),
745 false
746 );
747 assert_eq!(cnt.load(SeqCst), 1);
748
749 assert_eq!(
750 cell.get_or_init(|| {
751 cnt.fetch_add(1, SeqCst);
752 false
753 }),
754 false
755 );
756 assert_eq!(cnt.load(SeqCst), 1);
757 });
758 })
759 .unwrap();
760 assert_eq!(cell.get(), Some(false));
761 assert_eq!(cnt.load(SeqCst), 1);
762 }
763
764 #[test]
765 fn once_bool_set() {
766 let cell = OnceBool::new();
767
768 assert!(cell.set(false).is_ok());
769 assert_eq!(cell.get(), Some(false));
770
771 assert!(cell.set(true).is_err());
772 assert_eq!(cell.get(), Some(false));
773 }
774 }
775
776 #[cfg(all(feature = "race", feature = "alloc"))]
777 mod race_once_box {
778 use std::sync::{
779 atomic::{AtomicUsize, Ordering::SeqCst},
780 Arc, Barrier,
781 };
782
783 use crossbeam_utils::thread::scope;
784 use once_cell::race::OnceBox;
785
786 #[derive(Default)]
787 struct Heap {
788 total: Arc<AtomicUsize>,
789 }
790
791 #[derive(Debug)]
792 struct Pebble<T> {
793 val: T,
794 total: Arc<AtomicUsize>,
795 }
796
797 impl<T> Drop for Pebble<T> {
798 fn drop(&mut self) {
799 self.total.fetch_sub(1, SeqCst);
800 }
801 }
802
803 impl Heap {
804 fn total(&self) -> usize {
805 self.total.load(SeqCst)
806 }
807 fn new_pebble<T>(&self, val: T) -> Pebble<T> {
808 self.total.fetch_add(1, SeqCst);
809 Pebble { val, total: Arc::clone(&self.total) }
810 }
811 }
812
813 #[test]
814 fn once_box_smoke_test() {
815 let heap = Heap::default();
816 let global_cnt = AtomicUsize::new(0);
817 let cell = OnceBox::new();
818 let b = Barrier::new(128);
819 scope(|s| {
820 for _ in 0..128 {
821 s.spawn(|_| {
822 let local_cnt = AtomicUsize::new(0);
823 cell.get_or_init(|| {
824 global_cnt.fetch_add(1, SeqCst);
825 local_cnt.fetch_add(1, SeqCst);
826 b.wait();
827 Box::new(heap.new_pebble(()))
828 });
829 assert_eq!(local_cnt.load(SeqCst), 1);
830
831 cell.get_or_init(|| {
832 global_cnt.fetch_add(1, SeqCst);
833 local_cnt.fetch_add(1, SeqCst);
834 Box::new(heap.new_pebble(()))
835 });
836 assert_eq!(local_cnt.load(SeqCst), 1);
837 });
838 }
839 })
840 .unwrap();
841 assert!(cell.get().is_some());
842 assert!(global_cnt.load(SeqCst) > 10);
843
844 assert_eq!(heap.total(), 1);
845 drop(cell);
846 assert_eq!(heap.total(), 0);
847 }
848
849 #[test]
850 fn once_box_set() {
851 let heap = Heap::default();
852 let cell = OnceBox::new();
853 assert!(cell.get().is_none());
854
855 assert!(cell.set(Box::new(heap.new_pebble("hello"))).is_ok());
856 assert_eq!(cell.get().unwrap().val, "hello");
857 assert_eq!(heap.total(), 1);
858
859 assert!(cell.set(Box::new(heap.new_pebble("world"))).is_err());
860 assert_eq!(cell.get().unwrap().val, "hello");
861 assert_eq!(heap.total(), 1);
862
863 drop(cell);
864 assert_eq!(heap.total(), 0);
865 }
866
867 #[test]
868 fn once_box_first_wins() {
869 let cell = OnceBox::new();
870 let val1 = 92;
871 let val2 = 62;
872
873 let b1 = Barrier::new(2);
874 let b2 = Barrier::new(2);
875 let b3 = Barrier::new(2);
876 scope(|s| {
877 s.spawn(|_| {
878 let r1 = cell.get_or_init(|| {
879 b1.wait();
880 b2.wait();
881 Box::new(val1)
882 });
883 assert_eq!(*r1, val1);
884 b3.wait();
885 });
886 b1.wait();
887 s.spawn(|_| {
888 let r2 = cell.get_or_init(|| {
889 b2.wait();
890 b3.wait();
891 Box::new(val2)
892 });
893 assert_eq!(*r2, val1);
894 });
895 })
896 .unwrap();
897
898 assert_eq!(cell.get(), Some(&val1));
899 }
900
901 #[test]
902 fn once_box_reentrant() {
903 let cell = OnceBox::new();
904 let res = cell.get_or_init(|| {
905 cell.get_or_init(|| Box::new("hello".to_string()));
906 Box::new("world".to_string())
907 });
908 assert_eq!(res, "hello");
909 }
910
911 #[test]
912 fn once_box_default() {
913 struct Foo;
914
915 let cell: OnceBox<Foo> = Default::default();
916 assert!(cell.get().is_none());
917 }
918 }