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