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