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