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