use once_spin::*; use std::{sync::mpsc::channel, thread}; #[test] fn smoke_once() { static O: Once<()> = Once::new(); let mut a = 0; O.call_once(|| a += 1); assert_eq!(a, 1); O.call_once(|| a += 1); assert_eq!(a, 1); } #[test] fn smoke_once_value() { static O: Once = Once::new(); let a = O.call_once(|| 1); assert_eq!(*a, 1); let b = O.call_once(|| 2); assert_eq!(*b, 1); } #[test] fn stampede_once() { static O: Once<()> = Once::new(); static mut RUN: bool = false; let (tx, rx) = channel(); for _ in 0..10 { let tx = tx.clone(); thread::spawn(move || { for _ in 0..4 { thread::yield_now() } unsafe { O.call_once(|| { assert!(!RUN); RUN = true; }); assert!(RUN); } tx.send(()).unwrap(); }); } unsafe { O.call_once(|| { assert!(!RUN); RUN = true; }); assert!(RUN); } for _ in 0..10 { rx.recv().unwrap(); } } #[test] fn try_get() { static INIT: Once = Once::new(); assert!(INIT.try_get().is_none()); INIT.call_once(|| 2); assert_eq!(INIT.try_get().map(|r| *r), Some(2)); } #[test] fn try_no_wait() { static INIT: Once = Once::new(); assert!(INIT.try_get().is_none()); thread::spawn(move || { INIT.call_once(|| loop {}); }); assert!(INIT.try_get().is_none()); } #[test] fn wait() { static INIT: Once = Once::new(); assert!(INIT.wait().is_none()); INIT.call_once(|| 3); assert_eq!(INIT.wait().map(|r| *r), Some(3)); } #[test] fn panic() { use std::panic; static INIT: Once<()> = Once::new(); let t = panic::catch_unwind(|| { INIT.call_once(|| panic!()); }); assert!(t.is_err()); let t = panic::catch_unwind(|| { INIT.call_once(|| {}); }); assert!(t.is_err()); }