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