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