4 sync
::atomic
::{AtomicUsize, Ordering::SeqCst}
,
7 use once_cell
::unsync
::{Lazy, OnceCell}
;
11 let c
= OnceCell
::new();
12 assert
!(c
.get().is_none());
14 assert_eq
!(c
.get(), Some(&92));
16 c
.get_or_init(|| panic
!("Kabom!"));
17 assert_eq
!(c
.get(), Some(&92));
21 fn once_cell_with_value() {
22 const CELL
: OnceCell
<i32> = OnceCell
::with_value(12);
24 assert_eq
!(cell
.get(), Some(&12));
28 fn once_cell_get_mut() {
29 let mut c
= OnceCell
::new();
30 assert
!(c
.get_mut().is_none());
32 *c
.get_mut().unwrap() += 2;
33 assert_eq
!(c
.get_mut(), Some(&mut 92));
38 static DROP_CNT
: AtomicUsize
= AtomicUsize
::new(0);
40 impl Drop
for Dropper
{
42 DROP_CNT
.fetch_add(1, SeqCst
);
46 let x
= OnceCell
::new();
47 x
.get_or_init(|| Dropper
);
48 assert_eq
!(DROP_CNT
.load(SeqCst
), 0);
50 assert_eq
!(DROP_CNT
.load(SeqCst
), 1);
54 fn unsync_once_cell_drop_empty() {
55 let x
= OnceCell
::<String
>::new();
61 let s
= OnceCell
::new();
63 assert
!(c
.get().is_none());
65 s
.set("hello".to_string()).unwrap();
67 assert_eq
!(c
.get().map(String
::as_str
), Some("hello"));
72 assert_eq
!(OnceCell
::from("value").get(), Some(&"value"));
73 assert_ne
!(OnceCell
::from("foo").get(), Some(&"bar"));
78 assert
!(OnceCell
::from("value") == OnceCell
::from("value"));
79 assert
!(OnceCell
::from("foo") != OnceCell
::from("bar"));
81 assert
!(OnceCell
::<String
>::new() == OnceCell
::new());
82 assert
!(OnceCell
::<String
>::new() != OnceCell
::from("value".to_owned()));
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()));
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\")");
104 let called
= Cell
::new(0);
105 let x
= Lazy
::new(|| {
106 called
.set(called
.get() + 1);
110 assert_eq
!(called
.get(), 0);
114 assert_eq
!(called
.get(), 1);
118 assert_eq
!(called
.get(), 1);
122 fn lazy_deref_mut() {
123 let called
= Cell
::new(0);
124 let mut x
= Lazy
::new(|| {
125 called
.set(called
.get() + 1);
129 assert_eq
!(called
.get(), 0);
133 assert_eq
!(called
.get(), 1);
137 assert_eq
!(called
.get(), 1);
142 static CALLED
: AtomicUsize
= AtomicUsize
::new(0);
145 impl Default
for Foo
{
146 fn default() -> Self {
147 CALLED
.fetch_add(1, SeqCst
);
152 let lazy
: Lazy
<std
::sync
::Mutex
<Foo
>> = <_
>::default();
154 assert_eq
!(CALLED
.load(SeqCst
), 0);
156 assert_eq
!(lazy
.lock().unwrap().0, 42);
157 assert_eq
!(CALLED
.load(SeqCst
), 1);
159 lazy
.lock().unwrap().0 = 21;
161 assert_eq
!(lazy
.lock().unwrap().0, 21);
162 assert_eq
!(CALLED
.load(SeqCst
), 1);
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 }
);
171 assert
!(matches
!(Lazy
::into_value(l
), Ok(92)));
175 #[cfg(feature = "std")]
176 fn lazy_poisoning() {
177 let x
: Lazy
<String
> = Lazy
::new(|| panic
!("kaboom"));
179 let res
= std
::panic
::catch_unwind(|| x
.len());
180 assert
!(res
.is_err());
185 fn aliasing_in_get() {
186 let x
= OnceCell
::new();
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 ---------------------------+
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
);
199 let r
= x
.get_or_init(|| Box
::new(92));
200 dangling_ref
.set(Some(r
));
203 eprintln
!("use after free: {:?}", dangling_ref
.get().unwrap());
207 // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
208 fn arrrrrrrrrrrrrrrrrrrrrr() {
209 let cell
= OnceCell
::new();
211 let s
= String
::new();
212 cell
.set(&s
).unwrap();
217 #[cfg(feature = "std")]
219 use std
::sync
::atomic
::{AtomicUsize, Ordering::SeqCst}
;
221 use crossbeam_utils
::thread
::scope
;
223 use once_cell
::sync
::{Lazy, OnceCell}
;
227 let c
= OnceCell
::new();
228 assert
!(c
.get().is_none());
231 c
.get_or_init(|| 92);
232 assert_eq
!(c
.get(), Some(&92));
236 c
.get_or_init(|| panic
!("Kabom!"));
237 assert_eq
!(c
.get(), Some(&92));
241 fn once_cell_with_value() {
242 static CELL
: OnceCell
<i32> = OnceCell
::with_value(12);
243 assert_eq
!(CELL
.get(), Some(&12));
247 fn once_cell_get_mut() {
248 let mut c
= OnceCell
::new();
249 assert
!(c
.get_mut().is_none());
251 *c
.get_mut().unwrap() += 2;
252 assert_eq
!(c
.get_mut(), Some(&mut 92));
256 fn once_cell_get_unchecked() {
257 let c
= OnceCell
::new();
260 assert_eq
!(c
.get_unchecked(), &92);
265 fn once_cell_drop() {
266 static DROP_CNT
: AtomicUsize
= AtomicUsize
::new(0);
268 impl Drop
for Dropper
{
270 DROP_CNT
.fetch_add(1, SeqCst
);
274 let x
= OnceCell
::new();
277 x
.get_or_init(|| Dropper
);
278 assert_eq
!(DROP_CNT
.load(SeqCst
), 0);
283 assert_eq
!(DROP_CNT
.load(SeqCst
), 1);
287 fn once_cell_drop_empty() {
288 let x
= OnceCell
::<String
>::new();
294 let s
= OnceCell
::new();
296 assert
!(c
.get().is_none());
298 s
.set("hello".to_string()).unwrap();
300 assert_eq
!(c
.get().map(String
::as_str
), Some("hello"));
304 fn get_or_try_init() {
305 let cell
: OnceCell
<String
> = OnceCell
::new();
306 assert
!(cell
.get().is_none());
309 std
::panic
::catch_unwind(|| cell
.get_or_try_init(|| -> Result
<_
, ()> { panic!() }
));
310 assert
!(res
.is_err());
311 assert
!(cell
.get().is_none());
313 assert_eq
!(cell
.get_or_try_init(|| Err(())), Err(()));
316 cell
.get_or_try_init(|| Ok
::<_
, ()>("hello".to_string())),
317 Ok(&"hello".to_string())
319 assert_eq
!(cell
.get(), Some(&"hello".to_string()));
324 let cell
: OnceCell
<String
> = OnceCell
::new();
326 s
.spawn(|_
| cell
.set("hello".to_string()));
327 let greeting
= cell
.wait();
328 assert_eq
!(greeting
, "hello")
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;
339 let cells
: Vec
<_
> = std
::iter
::repeat_with(|| (Barrier
::new(n_threads
), OnceCell
::new()))
343 for t
in 0..n_threads
{
346 for (i
, (b
, s
)) in cells
.iter().enumerate() {
348 let j
= if t
% 2 == 0 { s.wait() }
else { s.get_or_init(|| i) }
;
359 assert_eq
!(OnceCell
::from("value").get(), Some(&"value"));
360 assert_ne
!(OnceCell
::from("foo").get(), Some(&"bar"));
364 fn partialeq_impl() {
365 assert
!(OnceCell
::from("value") == OnceCell
::from("value"));
366 assert
!(OnceCell
::from("foo") != OnceCell
::from("bar"));
368 assert
!(OnceCell
::<String
>::new() == OnceCell
::new());
369 assert
!(OnceCell
::<String
>::new() != OnceCell
::from("value".to_owned()));
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()));
383 let cell
= OnceCell
::new();
384 assert_eq
!(format
!("{:#?}", cell
), "OnceCell(Uninit)");
385 cell
.set(vec
!["hello", "world"]).unwrap();
387 format
!("{:#?}", cell
),
398 #[cfg_attr(miri, ignore)] // miri doesn't support processes
399 fn reentrant_init() {
401 let mut exe
= std
::env
::current_exe().unwrap();
404 exe
.push("examples");
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());
416 child
: std
::process
::Child
,
419 impl Drop
for Guard
{
421 let _
= self.child
.kill();
428 let called
= AtomicUsize
::new(0);
429 let x
= Lazy
::new(|| {
430 called
.fetch_add(1, SeqCst
);
434 assert_eq
!(called
.load(SeqCst
), 0);
440 assert_eq
!(called
.load(SeqCst
), 1);
447 assert_eq
!(called
.load(SeqCst
), 1);
451 fn lazy_deref_mut() {
452 let called
= AtomicUsize
::new(0);
453 let mut x
= Lazy
::new(|| {
454 called
.fetch_add(1, SeqCst
);
458 assert_eq
!(called
.load(SeqCst
), 0);
462 assert_eq
!(called
.load(SeqCst
), 1);
466 assert_eq
!(called
.load(SeqCst
), 1);
471 static CALLED
: AtomicUsize
= AtomicUsize
::new(0);
474 impl Default
for Foo
{
475 fn default() -> Self {
476 CALLED
.fetch_add(1, SeqCst
);
481 let lazy
: Lazy
<std
::sync
::Mutex
<Foo
>> = <_
>::default();
483 assert_eq
!(CALLED
.load(SeqCst
), 0);
485 assert_eq
!(lazy
.lock().unwrap().0, 42);
486 assert_eq
!(CALLED
.load(SeqCst
), 1);
488 lazy
.lock().unwrap().0 = 21;
490 assert_eq
!(lazy
.lock().unwrap().0, 21);
491 assert_eq
!(CALLED
.load(SeqCst
), 1);
496 static XS
: Lazy
<Vec
<i32>> = Lazy
::new(|| {
497 let mut xs
= Vec
::new();
505 assert_eq
!(&*XS
, &vec
![1, 2, 3]);
509 assert_eq
!(&*XS
, &vec
![1, 2, 3]);
513 fn static_lazy_via_fn() {
514 fn xs() -> &'
static Vec
<i32> {
515 static XS
: OnceCell
<Vec
<i32>> = OnceCell
::new();
517 let mut xs
= Vec
::new();
524 assert_eq
!(xs(), &vec
![1, 2, 3]);
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 }
);
533 assert
!(matches
!(Lazy
::into_value(l
), Ok(92)));
537 fn lazy_poisoning() {
538 let x
: Lazy
<String
> = Lazy
::new(|| panic
!("kaboom"));
540 let res
= std
::panic
::catch_unwind(|| x
.len());
541 assert
!(res
.is_err());
546 fn once_cell_is_sync_send() {
547 fn assert_traits
<T
: Send
+ Sync
>() {}
548 assert_traits
::<OnceCell
<String
>>();
549 assert_traits
::<Lazy
<String
>>();
553 fn eval_once_macro() {
554 macro_rules
! eval_once
{
558 static ONCE_CELL
: OnceCell
<$ty
> = OnceCell
::new();
562 ONCE_CELL
.get_or_init(init
)
566 let fib
: &'
static Vec
<i32> = eval_once
! {
568 let mut res
= vec
![1, 1];
570 let next
= res
[i
] + res
[i
+ 1];
576 assert_eq
!(fib
[5], 8)
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() {
585 const MSG
: &str = "Hello, World";
587 for _
in 0..n_tries
{
588 let cell
: OnceCell
<String
> = OnceCell
::new();
590 for _
in 0..n_readers
{
591 scope
.spawn(|_
| loop {
592 if let Some(msg
) = cell
.get() {
593 assert_eq
!(msg
, MSG
);
598 for _
in 0..n_writers
{
599 let _
= scope
.spawn(|_
| cell
.set(MSG
.to_owned()));
607 #[cfg_attr(miri, ignore)] // miri doesn't support Barrier
608 fn get_does_not_block() {
609 use std
::sync
::Barrier
;
611 let cell
= OnceCell
::new();
612 let barrier
= Barrier
::new(2);
615 cell
.get_or_init(|| {
622 assert_eq
!(cell
.get(), None
);
626 assert_eq
!(cell
.get(), Some(&"hello".to_string()));
630 // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669
631 fn arrrrrrrrrrrrrrrrrrrrrr() {
632 let cell
= OnceCell
::new();
634 let s
= String
::new();
635 cell
.set(&s
).unwrap();
640 #[cfg(feature = "race")]
645 atomic
::{AtomicUsize, Ordering::SeqCst}
,
650 use crossbeam_utils
::thread
::scope
;
652 use once_cell
::race
::{OnceBool, OnceNonZeroUsize}
;
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();
662 cell
.get_or_init(|| {
663 cnt
.fetch_add(1, SeqCst
);
668 assert_eq
!(cnt
.load(SeqCst
), 1);
671 cell
.get_or_init(|| {
672 cnt
.fetch_add(1, SeqCst
);
677 assert_eq
!(cnt
.load(SeqCst
), 1);
681 assert_eq
!(cell
.get(), Some(val
));
682 assert_eq
!(cnt
.load(SeqCst
), 1);
686 fn once_non_zero_usize_set() {
687 let val1
= NonZeroUsize
::new(92).unwrap();
688 let val2
= NonZeroUsize
::new(62).unwrap();
690 let cell
= OnceNonZeroUsize
::new();
692 assert
!(cell
.set(val1
).is_ok());
693 assert_eq
!(cell
.get(), Some(val1
));
695 assert
!(cell
.set(val2
).is_err());
696 assert_eq
!(cell
.get(), Some(val1
));
700 fn once_non_zero_usize_first_wins() {
701 let val1
= NonZeroUsize
::new(92).unwrap();
702 let val2
= NonZeroUsize
::new(62).unwrap();
704 let cell
= OnceNonZeroUsize
::new();
706 let b1
= Barrier
::new(2);
707 let b2
= Barrier
::new(2);
708 let b3
= Barrier
::new(2);
711 let r1
= cell
.get_or_init(|| {
716 assert_eq
!(r1
, val1
);
721 let r2
= cell
.get_or_init(|| {
726 assert_eq
!(r2
, val1
);
731 assert_eq
!(cell
.get(), Some(val1
));
735 fn once_bool_smoke_test() {
736 let cnt
= AtomicUsize
::new(0);
737 let cell
= OnceBool
::new();
741 cell
.get_or_init(|| {
742 cnt
.fetch_add(1, SeqCst
);
747 assert_eq
!(cnt
.load(SeqCst
), 1);
750 cell
.get_or_init(|| {
751 cnt
.fetch_add(1, SeqCst
);
756 assert_eq
!(cnt
.load(SeqCst
), 1);
760 assert_eq
!(cell
.get(), Some(false));
761 assert_eq
!(cnt
.load(SeqCst
), 1);
766 let cell
= OnceBool
::new();
768 assert
!(cell
.set(false).is_ok());
769 assert_eq
!(cell
.get(), Some(false));
771 assert
!(cell
.set(true).is_err());
772 assert_eq
!(cell
.get(), Some(false));
776 #[cfg(all(feature = "race", feature = "alloc"))]
779 atomic
::{AtomicUsize, Ordering::SeqCst}
,
783 use crossbeam_utils
::thread
::scope
;
784 use once_cell
::race
::OnceBox
;
788 total
: Arc
<AtomicUsize
>,
794 total
: Arc
<AtomicUsize
>,
797 impl<T
> Drop
for Pebble
<T
> {
799 self.total
.fetch_sub(1, SeqCst
);
804 fn total(&self) -> usize {
805 self.total
.load(SeqCst
)
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) }
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);
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
);
827 Box
::new(heap
.new_pebble(()))
829 assert_eq
!(local_cnt
.load(SeqCst
), 1);
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(()))
836 assert_eq
!(local_cnt
.load(SeqCst
), 1);
841 assert
!(cell
.get().is_some());
842 assert
!(global_cnt
.load(SeqCst
) > 10);
844 assert_eq
!(heap
.total(), 1);
846 assert_eq
!(heap
.total(), 0);
851 let heap
= Heap
::default();
852 let cell
= OnceBox
::new();
853 assert
!(cell
.get().is_none());
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);
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);
864 assert_eq
!(heap
.total(), 0);
868 fn once_box_first_wins() {
869 let cell
= OnceBox
::new();
873 let b1
= Barrier
::new(2);
874 let b2
= Barrier
::new(2);
875 let b3
= Barrier
::new(2);
878 let r1
= cell
.get_or_init(|| {
883 assert_eq
!(*r1
, val1
);
888 let r2
= cell
.get_or_init(|| {
893 assert_eq
!(*r2
, val1
);
898 assert_eq
!(cell
.get(), Some(&val1
));
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())
908 assert_eq
!(res
, "hello");
912 fn once_box_default() {
915 let cell
: OnceBox
<Foo
> = Default
::default();
916 assert
!(cell
.get().is_none());